summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2017-09-01 18:27:15 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2018-01-08 09:41:53 +0000
commit69496d4e22fb6a8805fbcfa798d9aca53621a2ac (patch)
tree788bb62a9981188fb82ad16ef61b1e9e8fdeb35d /tests/auto/corelib
parent9c53f4d33a1953bc84e5b5e8bbef14db375bb180 (diff)
Introduce QAbstractItemModel::checkIndex()
When implementing a custom model there's the habit, in each and every function that takes a QModelIndex, to carefully checking the index passed by the caller. This index is checked for "legality" (*): does the index belong to this model, is the index pointing to an existing row and column, and so on. These checks are hand-rolled and, as such, slightly different and possibly incomplete (i.e. wrong) every time. What's worse, these checks are implemented via "ordinary" code (if statements). However, passing an illegal index to a QAIM function is a precondition violation, and as such does not (and must not) be checked in ordinary conditions, as it triggers undefined behavior. On the other hand, while debugging a custom model or a custom hierarchy of (proxy) models, having such checks in place can be a significant aid. Enter checkIndex(): a debugging helper for QAbstractItemModel and its subclasses. checkIndex() centralizes the checks for legality of a given index. User code is free to assert on it, or have some other fallback mechanism in case a check fails. (*) Using "legality" here instead of "validity" in order to avoid confusion between QModelIndex::isValid() and what checkIndex() really does. [ChangeLog][QtCore][QAbstractItemModel] Added QAbstractItemModel::checkIndex(), a debugging function for QAbstractItemModel subclasses. Change-Id: I1eea0586b1ac3ededdbfbf46759145022dc5ad86 Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com> Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'tests/auto/corelib')
-rw-r--r--tests/auto/corelib/itemmodels/qabstractitemmodel/qabstractitemmodel.pro2
-rw-r--r--tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp72
2 files changed, 73 insertions, 1 deletions
diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/qabstractitemmodel.pro b/tests/auto/corelib/itemmodels/qabstractitemmodel/qabstractitemmodel.pro
index 7480bd45f6..dc7362e442 100644
--- a/tests/auto/corelib/itemmodels/qabstractitemmodel/qabstractitemmodel.pro
+++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/qabstractitemmodel.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qabstractitemmodel
-QT = core testlib
+QT = core testlib gui
mtdir = ../../../other/modeltest
INCLUDEPATH += $$PWD/$${mtdir}
diff --git a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
index 9f67ccd9c9..b960ca9220 100644
--- a/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
+++ b/tests/auto/corelib/itemmodels/qabstractitemmodel/tst_qabstractitemmodel.cpp
@@ -31,6 +31,7 @@
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QStringListModel>
+#include <QtGui/QStandardItemModel>
#include "dynamictreemodel.h"
@@ -105,6 +106,8 @@ private slots:
void testFunctionPointerSignalConnection();
+ void checkIndex();
+
private:
DynamicTreeModel *m_model;
};
@@ -2283,6 +2286,75 @@ void tst_QAbstractItemModel::testFunctionPointerSignalConnection()
// model.rowsInserted(QModelIndex(), 0, 0);
}
+void tst_QAbstractItemModel::checkIndex()
+{
+ const QRegularExpression ignorePattern("^Index QModelIndex");
+
+ // checkIndex is QAbstractItemModel API; using QStandardItem as an easy
+ // way to build a tree model
+ QStandardItemModel model;
+ QStandardItem *topLevel = new QStandardItem("topLevel");
+ model.appendRow(topLevel);
+
+ topLevel->appendRow(new QStandardItem("child1"));
+ topLevel->appendRow(new QStandardItem("child2"));
+
+ QVERIFY(model.checkIndex(QModelIndex()));
+ QVERIFY(model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QVERIFY(model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(QModelIndex(), QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ QModelIndex topLevelIndex = model.index(0, 0);
+ QVERIFY(topLevelIndex.isValid());
+ QVERIFY(model.checkIndex(topLevelIndex));
+ QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QVERIFY(model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ QModelIndex childIndex = model.index(0, 0, topLevelIndex);
+ QVERIFY(childIndex.isValid());
+ QVERIFY(model.checkIndex(childIndex));
+ QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ childIndex = model.index(1, 0, topLevelIndex);
+ QVERIFY(childIndex.isValid());
+ QVERIFY(model.checkIndex(childIndex));
+ QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ topLevel->removeRow(1);
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(childIndex));
+ QVERIFY(model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(childIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ QStandardItemModel model2;
+ model2.appendRow(new QStandardItem("otherTopLevel"));
+ topLevelIndex = model2.index(0, 0);
+ QVERIFY(topLevelIndex.isValid());
+ QVERIFY(model2.checkIndex(topLevelIndex));
+ QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QVERIFY(model2.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(topLevelIndex));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::DoNotUseParent));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::ParentIsInvalid));
+ QTest::ignoreMessage(QtWarningMsg, ignorePattern);
+ QVERIFY(!model.checkIndex(topLevelIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid));
+}
QTEST_MAIN(tst_QAbstractItemModel)
#include "tst_qabstractitemmodel.moc"