diff options
author | Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com> | 2015-11-23 18:35:02 -0800 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com> | 2015-12-07 16:10:24 +0000 |
commit | d2305265af0552f9fcab4c93bed6b93e25a28f78 (patch) | |
tree | 8a0ac1dee758fea8bd2ba2ff5f3fb4008c426252 | |
parent | f9f99c43fbea600f61d065b30a5453e95dfa6ade (diff) |
Auto-tests for fast model updates while flicking
Stress testing might sound unfair, but it can happen that
the user is flicking the view while the model gets updated
resulting in an internally inconsistent state. We need to
cover this and start working on a solution.
The test is initially blacklisted as it's not expected to
pass all the time.
Task-number: QTBUG 48870
Change-Id: I7c1e4fd1876f52dd2dad5a28584b571753ebe69a
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
-rw-r--r-- | src/quick/items/qquickitemview_p_p.h | 4 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/BLACKLIST | 2 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/data/qtbug48870.qml | 24 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 132 |
4 files changed, 160 insertions, 2 deletions
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 8af703eb03..ea1c7c494a 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE -class FxViewItem +class Q_AUTOTEST_EXPORT FxViewItem { public: FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached); @@ -123,7 +123,7 @@ public: }; -class QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener +class Q_AUTOTEST_EXPORT QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener { Q_DECLARE_PUBLIC(QQuickItemView) public: diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index 269696ce8c..02adeacf05 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -2,3 +2,5 @@ * [enforceRange_withoutHighlight] osx +[QTBUG_48870_fastModelUpdates] +* diff --git a/tests/auto/quick/qquicklistview/data/qtbug48870.qml b/tests/auto/quick/qquicklistview/data/qtbug48870.qml new file mode 100644 index 0000000000..217f58af48 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug48870.qml @@ -0,0 +1,24 @@ +import QtQuick 2.6 + +Rectangle { + width: 500 + height: 500 + color: "blue" + + ListView { + objectName: "list" + anchors.fill: parent + model: testModel + + delegate: Rectangle { + height: 50 + width: ListView.view ? ListView.view.width : height + color: "green" + + Text { + anchors.centerIn: parent + text: "Item " + index + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index a5de266636..ce2337ccb2 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -40,6 +40,7 @@ #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlexpression.h> #include <QtQml/qqmlincubator.h> +#include <QtQuick/private/qquickitemview_p_p.h> #include <QtQuick/private/qquicklistview_p.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQml/private/qqmlobjectmodel_p.h> @@ -249,6 +250,7 @@ private slots: void contentHeightWithDelayRemove_data(); void QTBUG_48044_currentItemNotVisibleAfterTransition(); + void QTBUG_48870_fastModelUpdates(); private: template <class T> void items(const QUrl &source); @@ -8295,6 +8297,136 @@ void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() QVERIFY(!currentPriv->culled); } +static bool testVisibleItems(const QQuickItemViewPrivate *priv, bool *nonUnique, FxViewItem **failItem, int *expectedIdx) +{ + QHash<QQuickItem*, int> uniqueItems; + + int skip = 0; + for (int i = 0; i < priv->visibleItems.count(); ++i) { + FxViewItem *item = priv->visibleItems.at(i); + if (!item) { + *failItem = Q_NULLPTR; + return false; + } +#if 0 + qDebug() << "\t" << item->index + << item->item + << item->position() + << (!item->item || QQuickItemPrivate::get(item->item)->culled ? "hidden" : "visible"); +#endif + if (item->index == -1) { + ++skip; + } else if (item->index != priv->visibleIndex + i - skip) { + *nonUnique = false; + *failItem = item; + *expectedIdx = priv->visibleIndex + i - skip; + return false; + } else if (uniqueItems.contains(item->item)) { + *nonUnique = true; + *failItem = item; + *expectedIdx = uniqueItems.find(item->item).value(); + return false; + } + + uniqueItems.insert(item->item, item->index); + } + + return true; +} + +class QTBUG_48870_Model : public QAbstractListModel +{ + Q_OBJECT + +public: + + QTBUG_48870_Model() + : QAbstractListModel() + , m_rowCount(20) + { + QTimer *t = new QTimer(this); + t->setInterval(500); + t->start(); + + qsrand(qHash(QDateTime::currentDateTime())); + connect(t, &QTimer::timeout, this, &QTBUG_48870_Model::updateModel); + } + + int rowCount(const QModelIndex &) const + { + return m_rowCount; + } + + QVariant data(const QModelIndex &, int) const + { + return QVariant(); + } + +public Q_SLOTS: + void updateModel() + { + if (m_rowCount > 10) { + for (int i = 0; i < 10; ++i) { + int rnum = qrand() % m_rowCount; + beginRemoveRows(QModelIndex(), rnum, rnum); + m_rowCount--; + endRemoveRows(); + } + } + if (m_rowCount < 20) { + for (int i = 0; i < 10; ++i) { + int rnum = qrand() % m_rowCount; + beginInsertRows(QModelIndex(), rnum, rnum); + m_rowCount++; + endInsertRows(); + } + } + } + +private: + int m_rowCount; +}; + +void tst_QQuickListView::QTBUG_48870_fastModelUpdates() +{ + QTBUG_48870_Model model; + + QQuickView *window = createView(); + QVERIFY(window); + QQmlContext *ctxt = window->rootContext(); + QVERIFY(ctxt); + ctxt->setContextProperty("testModel", &model); + + window->setSource(testFileUrl("qtbug48870.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + QQuickItemViewPrivate *priv = QQuickItemViewPrivate::get(listview); + bool nonUnique; + FxViewItem *item = Q_NULLPTR; + int expectedIdx; + QVERIFY(testVisibleItems(priv, &nonUnique, &item, &expectedIdx)); + + for (int i = 0; i < 10; i++) { + QTest::qWait(100); + QVERIFY2(testVisibleItems(priv, &nonUnique, &item, &expectedIdx), + qPrintable(!item ? QString("Unexpected null item") + : nonUnique ? QString("Non-unique item at %1 and %2").arg(item->index).arg(expectedIdx) + : QString("Found index %1, expected index is %3").arg(item->index).arg(expectedIdx))); + if (i % 3 != 0) { + if (i & 1) + flick(window, QPoint(100, 200), QPoint(100, 0), 100); + else + flick(window, QPoint(100, 200), QPoint(100, 400), 100); + } + } + + delete window; +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" |