diff --git a/autotests/libs/entitytreemodeltest.cpp b/autotests/libs/entitytreemodeltest.cpp index 04638ef53..2c3dc5c54 100644 --- a/autotests/libs/entitytreemodeltest.cpp +++ b/autotests/libs/entitytreemodeltest.cpp @@ -1,665 +1,657 @@ /* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "fakeserverdata.h" #include "fakesession.h" #include "fakemonitor.h" #include "modelspy.h" #include "imapparser_p.h" #include "entitytreemodel.h" #include #include static const QString serverContent1 = QStringLiteral( // The format of these lines are first a type, either 'C' or 'I' for Item and collection. // The dashes show the depth in the hierarchy // Collections have a list of mimetypes they can contain, followed by an optional // displayName which is put into the EntityDisplayAttribute, followed by an optional order // which is the order in which the collections are returned from the job to the ETM. "- C (inode/directory) 'Col 1' 4" "- - C (text/directory, message/rfc822) 'Col 2' 3" // Items just have the mimetype they contain in the payload. "- - - I text/directory 'Item 1'" "- - - I text/directory 'Item 2'" "- - - I message/rfc822 'Item 3'" "- - - I message/rfc822 'Item 4'" "- - C (text/directory) 'Col 3' 3" "- - - C (text/directory) 'Col 4' 2" "- - - - C (text/directory) 'Col 5' 1" // <-- First collection to be returned "- - - - - I text/directory 'Item 5'" "- - - - - I text/directory 'Item 6'" "- - - - I text/directory 'Item 7'" "- - - I text/directory 'Item 8'" "- - - I text/directory 'Item 9'" "- - C (message/rfc822) 'Col 6' 3" "- - - I message/rfc822 'Item 10'" "- - - I message/rfc822 'Item 11'" "- - C (text/directory, message/rfc822) 'Col 7' 3" "- - - I text/directory 'Item 12'" "- - - I text/directory 'Item 13'" "- - - I message/rfc822 'Item 14'" "- - - I message/rfc822 'Item 15'"); /** * This test verifies that the ETM reacts as expected to signals from the monitor. * * The tested ETM is only talking to fake components so the reaction of the ETM to each signal can be tested. * * WARNING: This test does no handle jobs issued by the model. It simply shortcuts (calls emitResult) them, and the connected * slots are never executed (because the eventloop is not run after emitResult is called). * This test therefore only tests the reaction of the model to signals of the monitor and not the overall behaviour. */ class EntityTreeModelTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testInitialFetch(); void testCollectionMove_data(); void testCollectionMove(); void testCollectionAdded_data(); void testCollectionAdded(); void testCollectionRemoved_data(); void testCollectionRemoved(); void testCollectionChanged_data(); void testCollectionChanged(); void testItemMove_data(); void testItemMove(); void testItemAdded_data(); void testItemAdded(); void testItemRemoved_data(); void testItemRemoved(); void testItemChanged_data(); void testItemChanged(); void testRemoveCollectionOnChanged(); private: QPair populateModel(const QString &serverContent, const QString &mimeType = QString()) { - FakeMonitor *fakeMonitor = new FakeMonitor(this); + const auto fakeMonitor = new FakeMonitor(this); fakeMonitor->setSession(m_fakeSession); fakeMonitor->setCollectionMonitored(Collection::root()); if (!mimeType.isEmpty()) { fakeMonitor->setMimeTypeMonitored(mimeType); } - EntityTreeModel *model = new EntityTreeModel(fakeMonitor, this); + const auto model = new EntityTreeModel(fakeMonitor, this); m_modelSpy = new ModelSpy{model, this}; - FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); - QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent); - serverData->setCommands(initialFetchResponse); + const auto serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + serverData->setCommands(FakeJobResponse::interpret(serverData, serverContent)); // Give the model a chance to populate QTest::qWait(100); return qMakePair(serverData, model); } private: ModelSpy *m_modelSpy = nullptr; FakeSession *m_fakeSession = nullptr; QByteArray m_sessionName; }; +QModelIndex firstMatchedIndex(const QAbstractItemModel &model, const QString pattern) +{ + if (pattern.isEmpty()) { + return {}; + } + const auto list = model.match(model.index(0, 0), Qt::DisplayRole, pattern, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + return list.first(); +} + void EntityTreeModelTest::initTestCase() { m_sessionName = "EntityTreeModelTest fake session"; m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); m_fakeSession->setAsDefaultSession(); qRegisterMetaType("QModelIndex"); } void EntityTreeModelTest::testInitialFetch() { - FakeMonitor *fakeMonitor = new FakeMonitor(this); + const auto fakeMonitor = new FakeMonitor(this); fakeMonitor->setSession(m_fakeSession); fakeMonitor->setCollectionMonitored(Collection::root()); - EntityTreeModel *model = new EntityTreeModel(fakeMonitor, this); + const auto model = new EntityTreeModel(fakeMonitor, this); - FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); - QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1); - serverData->setCommands(initialFetchResponse); + const auto serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + serverData->setCommands(FakeJobResponse::interpret(serverData, serverContent1)); - m_modelSpy = new ModelSpy{model, this}; + m_modelSpy = new ModelSpy(model, this); m_modelSpy->startSpying(); const QList expectedSignals { // First the model gets a signal about the first collection to be returned, which is not a top-level collection. // It uses the parentCollection hierarchy to put placeholder collections in the model until the root is reached. // Then it inserts only one row and emits the correct signals. After that, when the other collections // arrive, dataChanged is emitted for them. {RowsAboutToBeInserted, 0, 0}, {RowsInserted, 0, 0}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 4")}}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 3")}}, // New collections are prepended {RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")}, {RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList{QStringLiteral("Col 2")}}, {RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")}, {RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList{QStringLiteral("Col 6")}}, {RowsAboutToBeInserted, 0, 0, QStringLiteral("Collection 1")}, {RowsInserted, 0, 0, QStringLiteral("Collection 1"), QVariantList{QStringLiteral("Col 7")}}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 1")}}, // The items in the collections are appended. {RowsAboutToBeInserted, 0, 3, QStringLiteral("Col 2")}, {RowsInserted, 0, 3, QStringLiteral("Col 2")}, {RowsAboutToBeInserted, 0, 1, QStringLiteral("Col 5")}, {RowsInserted, 0, 1, QStringLiteral("Col 5")}, {RowsAboutToBeInserted, 1, 1, QStringLiteral("Col 4")}, {RowsInserted, 1, 1, QStringLiteral("Col 4")}, {RowsAboutToBeInserted, 1, 2, QStringLiteral("Col 3")}, {RowsInserted, 1, 2, QStringLiteral("Col 3")}, {RowsAboutToBeInserted, 0, 1, QStringLiteral("Col 6")}, {RowsInserted, 0, 1, QStringLiteral("Col 6")}, {RowsAboutToBeInserted, 0, 3, QStringLiteral("Col 7")}, {RowsInserted, 0, 3, QStringLiteral("Col 7")}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 1")}}, {DataChanged, 3, 3, QVariantList{QStringLiteral("Col 3")}}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 5")}}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 4")}}, {DataChanged, 2, 2, QVariantList{QStringLiteral("Col 2")}}, {DataChanged, 1, 1, QVariantList{QStringLiteral("Col 7")}}, {DataChanged, 0, 0, QVariantList{QStringLiteral("Col 6")}} }; m_modelSpy->setExpectedSignals(expectedSignals); // Give the model a chance to run the event loop to process the signals. QTest::qWait(10); // We get all the signals we expected. QTRY_VERIFY(m_modelSpy->expectedSignals().isEmpty()); QTest::qWait(10); // We didn't get signals we didn't expect. QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testCollectionMove_data() { QTest::addColumn("serverContent"); QTest::addColumn("movedCollection"); QTest::addColumn("targetCollection"); QTest::newRow("move-collection01") << serverContent1 << "Col 5" << "Col 1"; QTest::newRow("move-collection02") << serverContent1 << "Col 5" << "Col 2"; QTest::newRow("move-collection03") << serverContent1 << "Col 5" << "Col 3"; QTest::newRow("move-collection04") << serverContent1 << "Col 5" << "Col 6"; QTest::newRow("move-collection05") << serverContent1 << "Col 5" << "Col 7"; QTest::newRow("move-collection06") << serverContent1 << "Col 3" << "Col 2"; QTest::newRow("move-collection07") << serverContent1 << "Col 3" << "Col 6"; QTest::newRow("move-collection08") << serverContent1 << "Col 3" << "Col 7"; QTest::newRow("move-collection09") << serverContent1 << "Col 7" << "Col 2"; QTest::newRow("move-collection10") << serverContent1 << "Col 7" << "Col 5"; QTest::newRow("move-collection11") << serverContent1 << "Col 7" << "Col 4"; QTest::newRow("move-collection12") << serverContent1 << "Col 7" << "Col 3"; } void EntityTreeModelTest::testCollectionMove() { QFETCH(QString, serverContent); QFETCH(QString, movedCollection); QFETCH(QString, targetCollection); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, movedCollection, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex movedIndex = list.first(); - QString sourceCollection = movedIndex.parent().data().toString(); - int sourceRow = movedIndex.row(); + const auto movedIndex = firstMatchedIndex(*model, movedCollection); + Q_ASSERT(movedIndex.isValid()); + const auto sourceCollection = movedIndex.parent().data().toString(); + const auto sourceRow = movedIndex.row(); - FakeCollectionMovedCommand *moveCommand = new FakeCollectionMovedCommand(movedCollection, sourceCollection, targetCollection, serverData); + const auto moveCommand = new FakeCollectionMovedCommand(movedCollection, sourceCollection, targetCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << moveCommand); + serverData->setCommands({moveCommand}); const QList expectedSignals { {RowsAboutToBeMoved, sourceRow, sourceRow, sourceCollection, 0, targetCollection, {movedCollection}}, {RowsMoved, sourceRow, sourceRow, sourceCollection, 0, targetCollection , {movedCollection}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a change to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testCollectionAdded_data() { QTest::addColumn("serverContent"); QTest::addColumn("addedCollection"); QTest::addColumn("parentCollection"); QTest::newRow("add-collection01") << serverContent1 << "new Collection" << "Col 1"; QTest::newRow("add-collection02") << serverContent1 << "new Collection" << "Col 2"; QTest::newRow("add-collection03") << serverContent1 << "new Collection" << "Col 3"; QTest::newRow("add-collection04") << serverContent1 << "new Collection" << "Col 4"; QTest::newRow("add-collection05") << serverContent1 << "new Collection" << "Col 5"; QTest::newRow("add-collection06") << serverContent1 << "new Collection" << "Col 6"; QTest::newRow("add-collection07") << serverContent1 << "new Collection" << "Col 7"; } void EntityTreeModelTest::testCollectionAdded() { QFETCH(QString, serverContent); QFETCH(QString, addedCollection); QFETCH(QString, parentCollection); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; - FakeCollectionAddedCommand *addCommand = new FakeCollectionAddedCommand(addedCollection, parentCollection, serverData); + const auto addCommand = new FakeCollectionAddedCommand(addedCollection, parentCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << addCommand); + serverData->setCommands({addCommand}); const QList expectedSignals { {RowsAboutToBeInserted, 0, 0, parentCollection, QVariantList{addedCollection}}, {RowsInserted, 0, 0, parentCollection, QVariantList{addedCollection}}, // The data changed signal comes from the item fetch job that is triggered because we have ImmediatePopulation enabled {DataChanged, 0, 0, parentCollection, QVariantList{addedCollection}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testCollectionRemoved_data() { QTest::addColumn("serverContent"); QTest::addColumn("removedCollection"); // The test suite doesn't handle this case yet. // QTest::newRow("remove-collection01") << serverContent1 << "Col 1"; QTest::newRow("remove-collection02") << serverContent1 << "Col 2"; QTest::newRow("remove-collection03") << serverContent1 << "Col 3"; QTest::newRow("remove-collection04") << serverContent1 << "Col 4"; QTest::newRow("remove-collection05") << serverContent1 << "Col 5"; QTest::newRow("remove-collection06") << serverContent1 << "Col 6"; QTest::newRow("remove-collection07") << serverContent1 << "Col 7"; } void EntityTreeModelTest::testCollectionRemoved() { QFETCH(QString, serverContent); QFETCH(QString, removedCollection); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedCollection, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex removedIndex = list.first(); - QString parentCollection = removedIndex.parent().data().toString(); - int sourceRow = removedIndex.row(); + const auto removedIndex = firstMatchedIndex(*model, removedCollection); + const auto parentCollection = removedIndex.parent().data().toString(); + const auto sourceRow = removedIndex.row(); - FakeCollectionRemovedCommand *removeCommand = new FakeCollectionRemovedCommand(removedCollection, parentCollection, serverData); + const auto removeCommand = new FakeCollectionRemovedCommand(removedCollection, parentCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << removeCommand); + serverData->setCommands({removeCommand}); const QList expectedSignals { {RowsAboutToBeRemoved, sourceRow, sourceRow, parentCollection, QVariantList{removedCollection}}, {RowsRemoved, sourceRow, sourceRow, parentCollection , QVariantList{removedCollection}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testCollectionChanged_data() { QTest::addColumn("serverContent"); QTest::addColumn("collectionName"); QTest::addColumn("monitoredMimeType"); QTest::newRow("change-collection01") << serverContent1 << "Col 1" << QString(); QTest::newRow("change-collection02") << serverContent1 << "Col 2" << QString(); QTest::newRow("change-collection03") << serverContent1 << "Col 3" << QString(); QTest::newRow("change-collection04") << serverContent1 << "Col 4" << QString(); QTest::newRow("change-collection05") << serverContent1 << "Col 5" << QString(); QTest::newRow("change-collection06") << serverContent1 << "Col 6" << QString(); QTest::newRow("change-collection07") << serverContent1 << "Col 7" << QString(); //Don't remove the parent due to a missing mimetype QTest::newRow("change-collection08") << serverContent1 << "Col 1" << QStringLiteral("message/rfc822"); } void EntityTreeModelTest::testCollectionChanged() { QFETCH(QString, serverContent); QFETCH(QString, collectionName); QFETCH(QString, monitoredMimeType); - QPair testDrivers = populateModel(serverContent, monitoredMimeType); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, collectionName, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex changedIndex = list.first(); - QString parentCollection = changedIndex.parent().data().toString(); + const auto changedIndex = firstMatchedIndex(*model, collectionName); + const auto parentCollection = changedIndex.parent().data().toString(); qDebug() << parentCollection; - int changedRow = changedIndex.row(); + const auto changedRow = changedIndex.row(); - FakeCollectionChangedCommand *changeCommand = new FakeCollectionChangedCommand(collectionName, parentCollection, serverData); + const auto changeCommand = new FakeCollectionChangedCommand(collectionName, parentCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << changeCommand); + serverData->setCommands({changeCommand}); const QList expectedSignals { {DataChanged, changedRow, changedRow, parentCollection, QVariantList{collectionName}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testItemMove_data() { QTest::addColumn("serverContent"); QTest::addColumn("movedItem"); QTest::addColumn("targetCollection"); QTest::newRow("move-item01") << serverContent1 << "Item 1" << "Col 7"; QTest::newRow("move-item02") << serverContent1 << "Item 5" << "Col 4"; // Move item to grandparent. QTest::newRow("move-item03") << serverContent1 << "Item 7" << "Col 5"; // Move item to sibling. QTest::newRow("move-item04") << serverContent1 << "Item 8" << "Col 5"; // Move item to nephew QTest::newRow("move-item05") << serverContent1 << "Item 8" << "Col 6"; // Move item to uncle QTest::newRow("move-item02") << serverContent1 << "Item 5" << "Col 3"; // Move item to great-grandparent. } void EntityTreeModelTest::testItemMove() { QFETCH(QString, serverContent); QFETCH(QString, movedItem); QFETCH(QString, targetCollection); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, movedItem, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex movedIndex = list.first(); - QString sourceCollection = movedIndex.parent().data().toString(); - int sourceRow = movedIndex.row(); + const auto movedIndex = firstMatchedIndex(*model, movedItem); + const auto sourceCollection = movedIndex.parent().data().toString(); + const auto sourceRow = movedIndex.row(); - QModelIndexList targetList = model->match(model->index(0, 0), Qt::DisplayRole, targetCollection, 1, Qt::MatchRecursive); - Q_ASSERT(!targetList.isEmpty()); - QModelIndex targetIndex = targetList.first(); - int targetRow = model->rowCount(targetIndex); + const auto targetIndex = firstMatchedIndex(*model, targetCollection); + const auto targetRow = model->rowCount(targetIndex); - FakeItemMovedCommand *moveCommand = new FakeItemMovedCommand(movedItem, sourceCollection, targetCollection, serverData); + const auto moveCommand = new FakeItemMovedCommand(movedItem, sourceCollection, targetCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << moveCommand); + serverData->setCommands({moveCommand}); const QList expectedSignals { //Currently moves are implemented as remove + insert in the ETM. {RowsAboutToBeRemoved, sourceRow, sourceRow, sourceCollection, QVariantList{movedItem}}, {RowsRemoved, sourceRow, sourceRow, sourceCollection, QVariantList{movedItem}}, {RowsAboutToBeInserted, targetRow, targetRow, targetCollection, QVariantList{movedItem}}, {RowsInserted, targetRow, targetRow, targetCollection, QVariantList{movedItem}}, // {RowsAboutToBeMoved, sourceRow, sourceRow, sourceCollection, targetRow, targetCollection, QVariantList{movedItem}}, // {RowsMoved, sourceRow, sourceRow, sourceCollection, targetRow, targetCollection, QVariantList{movedItem}}, }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testItemAdded_data() { QTest::addColumn("serverContent"); QTest::addColumn("addedItem"); QTest::addColumn("parentCollection"); QTest::newRow("add-item01") << serverContent1 << "new Item" << "Col 1"; QTest::newRow("add-item02") << serverContent1 << "new Item" << "Col 2"; QTest::newRow("add-item03") << serverContent1 << "new Item" << "Col 3"; QTest::newRow("add-item04") << serverContent1 << "new Item" << "Col 4"; QTest::newRow("add-item05") << serverContent1 << "new Item" << "Col 5"; QTest::newRow("add-item06") << serverContent1 << "new Item" << "Col 6"; QTest::newRow("add-item07") << serverContent1 << "new Item" << "Col 7"; } void EntityTreeModelTest::testItemAdded() { QFETCH(QString, serverContent); QFETCH(QString, addedItem); QFETCH(QString, parentCollection); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, parentCollection, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex parentIndex = list.first(); - int targetRow = model->rowCount(parentIndex); + const auto parentIndex = firstMatchedIndex(*model, parentCollection); + const auto targetRow = model->rowCount(parentIndex); - FakeItemAddedCommand *addedCommand = new FakeItemAddedCommand(addedItem, parentCollection, serverData); + const auto addedCommand = new FakeItemAddedCommand(addedItem, parentCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << addedCommand); + serverData->setCommands({addedCommand}); const QList expectedSignals { {RowsAboutToBeInserted, targetRow, targetRow, parentCollection, QVariantList{addedItem}}, {RowsInserted, targetRow, targetRow, parentCollection, QVariantList{addedItem}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testItemRemoved_data() { QTest::addColumn("serverContent"); QTest::addColumn("removedItem"); QTest::newRow("remove-item01") << serverContent1 << "Item 1"; QTest::newRow("remove-item02") << serverContent1 << "Item 2"; QTest::newRow("remove-item03") << serverContent1 << "Item 3"; QTest::newRow("remove-item04") << serverContent1 << "Item 4"; QTest::newRow("remove-item05") << serverContent1 << "Item 5"; QTest::newRow("remove-item06") << serverContent1 << "Item 6"; QTest::newRow("remove-item07") << serverContent1 << "Item 7"; QTest::newRow("remove-item08") << serverContent1 << "Item 8"; QTest::newRow("remove-item09") << serverContent1 << "Item 9"; QTest::newRow("remove-item10") << serverContent1 << "Item 10"; QTest::newRow("remove-item11") << serverContent1 << "Item 11"; QTest::newRow("remove-item12") << serverContent1 << "Item 12"; QTest::newRow("remove-item13") << serverContent1 << "Item 13"; QTest::newRow("remove-item14") << serverContent1 << "Item 14"; QTest::newRow("remove-item15") << serverContent1 << "Item 15"; } void EntityTreeModelTest::testItemRemoved() { QFETCH(QString, serverContent); QFETCH(QString, removedItem); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedItem, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex removedIndex = list.first(); - const QString sourceCollection = removedIndex.parent().data().toString(); - int sourceRow = removedIndex.row(); + const auto removedIndex = firstMatchedIndex(*model, removedItem); + const auto sourceCollection = removedIndex.parent().data().toString(); + const auto sourceRow = removedIndex.row(); - FakeItemRemovedCommand *removeCommand = new FakeItemRemovedCommand(removedItem, sourceCollection, serverData); + const auto removeCommand = new FakeItemRemovedCommand(removedItem, sourceCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << removeCommand); + serverData->setCommands({removeCommand}); const QList expectedSignals { {RowsAboutToBeRemoved, sourceRow, sourceRow, sourceCollection, QVariantList{removedItem}}, {RowsRemoved, sourceRow, sourceRow, sourceCollection, QVariantList{removedItem}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testItemChanged_data() { QTest::addColumn("serverContent"); QTest::addColumn("changedItem"); QTest::newRow("change-item01") << serverContent1 << "Item 1"; QTest::newRow("change-item02") << serverContent1 << "Item 2"; QTest::newRow("change-item03") << serverContent1 << "Item 3"; QTest::newRow("change-item04") << serverContent1 << "Item 4"; QTest::newRow("change-item05") << serverContent1 << "Item 5"; QTest::newRow("change-item06") << serverContent1 << "Item 6"; QTest::newRow("change-item07") << serverContent1 << "Item 7"; QTest::newRow("change-item08") << serverContent1 << "Item 8"; QTest::newRow("change-item09") << serverContent1 << "Item 9"; QTest::newRow("change-item10") << serverContent1 << "Item 10"; QTest::newRow("change-item11") << serverContent1 << "Item 11"; QTest::newRow("change-item12") << serverContent1 << "Item 12"; QTest::newRow("change-item13") << serverContent1 << "Item 13"; QTest::newRow("change-item14") << serverContent1 << "Item 14"; QTest::newRow("change-item15") << serverContent1 << "Item 15"; } void EntityTreeModelTest::testItemChanged() { QFETCH(QString, serverContent); QFETCH(QString, changedItem); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, changedItem, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex changedIndex = list.first(); - QString parentCollection = changedIndex.parent().data().toString(); - int sourceRow = changedIndex.row(); + const auto changedIndex = firstMatchedIndex(*model, changedItem); + const auto parentCollection = changedIndex.parent().data().toString(); + const auto sourceRow = changedIndex.row(); - FakeItemChangedCommand *changeCommand = new FakeItemChangedCommand(changedItem, parentCollection, serverData); + const auto changeCommand = new FakeItemChangedCommand(changedItem, parentCollection, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << changeCommand); + serverData->setCommands({changeCommand}); const QList expectedSignals { {DataChanged, sourceRow, sourceRow, QVariantList{changedItem}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void EntityTreeModelTest::testRemoveCollectionOnChanged() { - const QString serverContent = QStringLiteral( - "- C (inode/directory, text/directory) 'Col 1' 2" - "- - C (text/directory) 'Col 2' 1" - "- - - I text/directory 'Item 1'"); - const QString collectionName = QStringLiteral("Col 2"); - const QString monitoredMimeType = QStringLiteral("text/directory"); - - QPair testDrivers = populateModel(serverContent, monitoredMimeType); - FakeServerData *serverData = testDrivers.first; - Akonadi::EntityTreeModel *model = testDrivers.second; - - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, collectionName, 1, Qt::MatchRecursive); - Q_ASSERT(!list.isEmpty()); - QModelIndex changedIndex = list.first(); - Akonadi::Collection changedCol = changedIndex.data(Akonadi::EntityTreeModel::CollectionRole).value(); - changedCol.setContentMimeTypes(QStringList() << QStringLiteral("foobar")); - QString parentCollection = changedIndex.parent().data().toString(); + const auto serverContent = QStringLiteral( + "- C (inode/directory, text/directory) 'Col 1' 2" + "- - C (text/directory) 'Col 2' 1" + "- - - I text/directory 'Item 1'" + ); + const auto collectionName = QStringLiteral("Col 2"); + const auto monitoredMimeType = QStringLiteral("text/directory"); + + const auto testDrivers = populateModel(serverContent, monitoredMimeType); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; + + const auto changedIndex = firstMatchedIndex(*model, collectionName); + auto changedCol = changedIndex.data(Akonadi::EntityTreeModel::CollectionRole).value(); + changedCol.setContentMimeTypes({QStringLiteral("foobar")}); + const auto parentCollection = changedIndex.parent().data().toString(); - FakeCollectionChangedCommand *changeCommand = new FakeCollectionChangedCommand(changedCol, serverData); + const auto changeCommand = new FakeCollectionChangedCommand(changedCol, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << changeCommand); + serverData->setCommands({changeCommand}); const QList expectedSignals { {RowsAboutToBeRemoved, changedIndex.row(), changedIndex.row(), parentCollection, QVariantList{collectionName}}, {RowsRemoved, changedIndex.row(), changedIndex.row(), parentCollection, QVariantList{collectionName}}, }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a chance to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } #include "entitytreemodeltest.moc" QTEST_MAIN(EntityTreeModelTest) diff --git a/autotests/libs/modelspy.cpp b/autotests/libs/modelspy.cpp index ec16f2708..cd6ed62a4 100644 --- a/autotests/libs/modelspy.cpp +++ b/autotests/libs/modelspy.cpp @@ -1,220 +1,220 @@ /* Copyright (c) 2009 Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "modelspy.h" #include #include ModelSpy::ModelSpy(QAbstractItemModel *model, QObject *parent) : QObject{parent}, m_model{model}, m_isSpying{false} { qRegisterMetaType("QModelIndex"); } bool ModelSpy::isEmpty() const { return QList::isEmpty() && m_expectedSignals.isEmpty(); } void ModelSpy::setExpectedSignals(const QList< ExpectedSignal > &expectedSignals) { m_expectedSignals = expectedSignals; } QList ModelSpy::expectedSignals() const { return m_expectedSignals; } void ModelSpy::verifySignal(SignalType type, const QModelIndex &parent, int start, int end) { ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); QCOMPARE(int(type), int(expectedSignal.signalType)); QCOMPARE(parent.data(), expectedSignal.parentData); QCOMPARE(start, expectedSignal.startRow); QCOMPARE(end, expectedSignal.endRow); if (!expectedSignal.newData.isEmpty()) { // TODO } } void ModelSpy::verifySignal(SignalType type, const QModelIndex &parent, int start, int end, const QModelIndex &destParent, int destStart) { ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); QCOMPARE(int(type), int(expectedSignal.signalType)); QCOMPARE(start, expectedSignal.startRow); QCOMPARE(end, expectedSignal.endRow); QCOMPARE(parent.data(), expectedSignal.sourceParentData); QCOMPARE(destParent.data(), expectedSignal.parentData); QCOMPARE(destStart, expectedSignal.destRow); QVariantList moveList; QModelIndex _parent = type == RowsAboutToBeMoved ? parent : destParent; int _start = type == RowsAboutToBeMoved ? start : destStart; int _end = type == RowsAboutToBeMoved ? end : destStart + (end - start); for (int row = _start; row <= _end; ++row) { moveList << m_model->index(row, 0, _parent).data(); } QCOMPARE(moveList, expectedSignal.newData); } void ModelSpy::verifySignal(SignalType type, const QModelIndex &topLeft, const QModelIndex &bottomRight) { QCOMPARE(type, DataChanged); ExpectedSignal expectedSignal = m_expectedSignals.takeFirst(); QCOMPARE(int(type), int(expectedSignal.signalType)); QModelIndex parent = topLeft.parent(); //This check won't work for toplevel indexes if (parent.isValid()) { if (expectedSignal.parentData.isValid()) { QCOMPARE(parent.data(), expectedSignal.parentData); } } QCOMPARE(topLeft.row(), expectedSignal.startRow); QCOMPARE(bottomRight.row(), expectedSignal.endRow); for (int i = 0, row = topLeft.row(); row <= bottomRight.row(); ++row, ++i) { QCOMPARE(expectedSignal.newData.at(i), m_model->index(row, 0, parent).data()); } } void ModelSpy::startSpying() { m_isSpying = true; // If a signal is connected to a slot multiple times, the slot gets called multiple times. // As we're doing start and stop spying all the time, we disconnect here first to make sure. disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex))); connect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(rowsRemoved(QModelIndex,int,int))); connect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); connect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(dataChanged(QModelIndex,QModelIndex))); } void ModelSpy::stopSpying() { m_isSpying = false; disconnect(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); disconnect(m_model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(rowsMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex))); } void ModelSpy::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsAboutToBeInserted, parent, start, end); } else { - append(QVariantList() << RowsAboutToBeInserted << QVariant::fromValue(parent) << start << end); + append(QVariantList{RowsAboutToBeInserted, QVariant::fromValue(parent), start, end}); } } void ModelSpy::rowsInserted(const QModelIndex &parent, int start, int end) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsInserted, parent, start, end); } else { - append(QVariantList() << RowsInserted << QVariant::fromValue(parent) << start << end); + append(QVariantList{RowsInserted, QVariant::fromValue(parent), start, end}); } } void ModelSpy::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsAboutToBeRemoved, parent, start, end); } else { - append(QVariantList() << RowsAboutToBeRemoved << QVariant::fromValue(parent) << start << end); + append(QVariantList{RowsAboutToBeRemoved, QVariant::fromValue(parent), start, end}); } } void ModelSpy::rowsRemoved(const QModelIndex &parent, int start, int end) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsRemoved, parent, start, end); } else { - append(QVariantList() << RowsRemoved << QVariant::fromValue(parent) << start << end); + append(QVariantList{RowsRemoved, QVariant::fromValue(parent), start, end}); } } void ModelSpy::rowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsAboutToBeMoved, srcParent, start, end, destParent, destStart); } else { - append(QVariantList() << RowsAboutToBeMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart); + append(QVariantList{RowsAboutToBeMoved, QVariant::fromValue(srcParent), start, end, QVariant::fromValue(destParent), destStart}); } } void ModelSpy::rowsMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart) { if (!m_expectedSignals.isEmpty()) { verifySignal(RowsMoved, srcParent, start, end, destParent, destStart); } else { - append(QVariantList() << RowsMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart); + append(QVariantList{RowsMoved, QVariant::fromValue(srcParent), start, end, QVariant::fromValue(destParent), destStart}); } } void ModelSpy::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (!m_expectedSignals.isEmpty()) { verifySignal(DataChanged, topLeft, bottomRight); } else { - append(QVariantList() << DataChanged << QVariant::fromValue(topLeft) << QVariant::fromValue(bottomRight)); + append(QVariantList{DataChanged, QVariant::fromValue(topLeft), QVariant::fromValue(bottomRight)}); } } diff --git a/autotests/libs/tagmodeltest.cpp b/autotests/libs/tagmodeltest.cpp index 07c1bdca4..874458b89 100644 --- a/autotests/libs/tagmodeltest.cpp +++ b/autotests/libs/tagmodeltest.cpp @@ -1,344 +1,337 @@ /* * Copyright 2015 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include "fakeserverdata.h" #include "fakesession.h" #include "fakemonitor.h" #include "modelspy.h" #include "tagmodel.h" #include "tagmodel_p.h" static const QString serverContent1 = QStringLiteral( "- T PLAIN 'Tag 1' 4" "- - T PLAIN 'Tag 2' 3" "- - - T PLAIN 'Tag 4' 1" "- - T PLAIN 'Tag 3' 2" "- T PLAIN 'Tag 5' 5"); class TagModelTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void testInitialFetch(); void testTagAdded_data(); void testTagAdded(); void testTagChanged_data(); void testTagChanged(); void testTagRemoved_data(); void testTagRemoved(); void testTagMoved_data(); void testTagMoved(); private: QPair populateModel(const QString &serverContent) { - FakeMonitor *fakeMonitor = new FakeMonitor(this); + const auto fakeMonitor = new FakeMonitor(this); fakeMonitor->setSession(m_fakeSession); fakeMonitor->setCollectionMonitored(Collection::root()); fakeMonitor->setTypeMonitored(Akonadi::Monitor::Tags); - TagModel *model = new TagModel(fakeMonitor, this); + const auto model = new TagModel(fakeMonitor, this); m_modelSpy = new ModelSpy{model, this}; - FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); - QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent); - serverData->setCommands(initialFetchResponse); + const auto serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + serverData->setCommands(FakeJobResponse::interpret(serverData, serverContent)); // Give the model a chance to populate QTest::qWait(100); return qMakePair(serverData, model); } private: ModelSpy *m_modelSpy = nullptr; FakeSession *m_fakeSession = nullptr; QByteArray m_sessionName; }; +QModelIndex firstMatchedIndex(const QAbstractItemModel &model, const QString pattern) +{ + if (pattern.isEmpty()) { + return {}; + } + const auto list = model.match(model.index(0, 0), Qt::DisplayRole, pattern, 1, Qt::MatchRecursive); + Q_ASSERT(!list.isEmpty()); + return list.first(); +} + void TagModelTest::initTestCase() { m_sessionName = "TagModelTest fake session"; m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); m_fakeSession->setAsDefaultSession(); qRegisterMetaType("QModelIndex"); } void TagModelTest::testInitialFetch() { - FakeMonitor *fakeMonitor = new FakeMonitor(this); + const auto fakeMonitor = new FakeMonitor(this); fakeMonitor->setSession(m_fakeSession); fakeMonitor->setCollectionMonitored(Collection::root()); - TagModel *model = new TagModel(fakeMonitor, this); + const auto model = new TagModel(fakeMonitor, this); - FakeServerData *serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); - QList initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1); + const auto serverData = new FakeServerData(model, m_fakeSession, fakeMonitor); + const auto initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1); serverData->setCommands(initialFetchResponse); m_modelSpy = new ModelSpy{model, this}; m_modelSpy->startSpying(); const QList expectedSignals { {RowsAboutToBeInserted, 0, 0}, {RowsInserted, 0, 0}, {RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 1")}, {RowsInserted, 0, 0, QStringLiteral("Tag 1")}, {RowsAboutToBeInserted, 1, 1, QStringLiteral("Tag 1")}, {RowsInserted, 1, 1, QStringLiteral("Tag 1")}, {RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 2")}, {RowsInserted, 0, 0, QStringLiteral("Tag 2")}, {RowsAboutToBeInserted, 1, 1}, {RowsInserted, 1, 1} }; m_modelSpy->setExpectedSignals(expectedSignals); // Give the model a chance to run the event loop to process the signals. QTest::qWait(10); // We get all the signals we expected. QTRY_VERIFY(m_modelSpy->expectedSignals().isEmpty()); QTest::qWait(10); // We didn't get signals we didn't expect. QVERIFY(m_modelSpy->isEmpty()); } void TagModelTest::testTagAdded_data() { QTest::addColumn("serverContent"); QTest::addColumn("addedTag"); QTest::addColumn("parentTag"); QTest::newRow("add-tag01") << serverContent1 << "new Tag" << "Tag 1"; QTest::newRow("add-tag02") << serverContent1 << "new Tag" << "Tag 2"; QTest::newRow("add-tag03") << serverContent1 << "new Tag" << "Tag 3"; QTest::newRow("add-tag04") << serverContent1 << "new Tag" << "Tag 4"; QTest::newRow("add-tag05") << serverContent1 << "new Tag" << "Tag 5"; } void TagModelTest::testTagAdded() { QFETCH(QString, serverContent); QFETCH(QString, addedTag); QFETCH(QString, parentTag); - QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::TagModel *model = testDrivers.second; - - const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, parentTag, 1, Qt::MatchRecursive); - QVERIFY(!list.isEmpty()); - const QModelIndex parentIndex = list.first(); - const int newRow = model->rowCount(parentIndex); + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; + const auto parentIndex = firstMatchedIndex(*model, parentTag); + const auto newRow = model->rowCount(parentIndex); - FakeTagAddedCommand *addCommand = new FakeTagAddedCommand(addedTag, parentTag, serverData); + const auto addCommand = new FakeTagAddedCommand(addedTag, parentTag, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << addCommand); + serverData->setCommands({addCommand}); const QList expectedSignals { {RowsAboutToBeInserted, newRow, newRow, parentTag, QVariantList{addedTag}}, {RowsInserted, newRow, newRow, parentTag, QVariantList{addedTag}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a change to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void TagModelTest::testTagChanged_data() { QTest::addColumn("serverContent"); QTest::addColumn("tagName"); QTest::newRow("change-tag01") << serverContent1 << "Tag 1"; QTest::newRow("change-tag02") << serverContent1 << "Tag 2"; QTest::newRow("change-tag03") << serverContent1 << "Tag 3"; QTest::newRow("change-tag04") << serverContent1 << "Tag 4"; QTest::newRow("change-tag05") << serverContent1 << "Tag 5"; } void TagModelTest::testTagChanged() { QFETCH(QString, serverContent); QFETCH(QString, tagName); - const QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::TagModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, tagName, 1, Qt::MatchRecursive); - QVERIFY(!list.isEmpty()); - const QModelIndex changedIndex = list.first(); - const QString parentTag = changedIndex.parent().data().toString(); - const int changedRow = changedIndex.row(); + const auto changedIndex = firstMatchedIndex(*model, tagName); + const auto parentTag = changedIndex.parent().data().toString(); + const auto changedRow = changedIndex.row(); - FakeTagChangedCommand *changeCommand = new FakeTagChangedCommand(tagName, parentTag, serverData); + const auto changeCommand = new FakeTagChangedCommand(tagName, parentTag, serverData); m_modelSpy->startSpying(); serverData->setCommands(QList() << changeCommand); const QList expectedSignals { {DataChanged, changedRow, changedRow, parentTag, QVariantList{tagName}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a change to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void TagModelTest::testTagRemoved_data() { QTest::addColumn("serverContent"); QTest::addColumn("removedTag"); QTest::newRow("remove-tag01") << serverContent1 << "Tag 1"; QTest::newRow("remove-tag02") << serverContent1 << "Tag 2"; QTest::newRow("remove-tag03") << serverContent1 << "Tag 3"; QTest::newRow("remove-tag04") << serverContent1 << "Tag 4"; QTest::newRow("remove-tag05") << serverContent1 << "Tag 5"; } void TagModelTest::testTagRemoved() { QFETCH(QString, serverContent); QFETCH(QString, removedTag); - const QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::TagModel *model = testDrivers.second; + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; - const QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, removedTag, 1, Qt::MatchRecursive); - QVERIFY(!list.isEmpty()); - const QModelIndex removedIndex = list.first(); - const QString parentTag = removedIndex.parent().data().toString(); - const int sourceRow = removedIndex.row(); + const auto removedIndex = firstMatchedIndex(*model, removedTag); + const auto parentTag = removedIndex.parent().data().toString(); + const auto sourceRow = removedIndex.row(); - - FakeTagRemovedCommand *removeCommand = new FakeTagRemovedCommand(removedTag, parentTag, serverData); + const auto removeCommand = new FakeTagRemovedCommand(removedTag, parentTag, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << removeCommand); + serverData->setCommands({removeCommand}); const auto removedTagList = QVariantList{removedTag}; const auto parentTagVariant = parentTag.isEmpty() ? QVariant{} : parentTag; const QList expectedSignals { ExpectedSignal{RowsAboutToBeRemoved, sourceRow, sourceRow, parentTagVariant, QVariantList{removedTag}}, ExpectedSignal{RowsRemoved, sourceRow, sourceRow, parentTagVariant, QVariantList{removedTag}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a change to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } void TagModelTest::testTagMoved_data() { QTest::addColumn("serverContent"); QTest::addColumn("changedTag"); QTest::addColumn("newParent"); QTest::newRow("move-tag01") << serverContent1 << "Tag 1" << "Tag 5"; QTest::newRow("move-tag02") << serverContent1 << "Tag 2" << "Tag 5"; QTest::newRow("move-tag03") << serverContent1 << "Tag 3" << "Tag 4"; QTest::newRow("move-tag04") << serverContent1 << "Tag 4" << "Tag 1"; QTest::newRow("move-tag05") << serverContent1 << "Tag 5" << "Tag 2"; QTest::newRow("move-tag06") << serverContent1 << "Tag 3" << QString(); QTest::newRow("move-tag07") << serverContent1 << "Tag 2" << QString(); } void TagModelTest::testTagMoved() { QFETCH(QString, serverContent); QFETCH(QString, changedTag); QFETCH(QString, newParent); - const QPair testDrivers = populateModel(serverContent); - FakeServerData *serverData = testDrivers.first; - Akonadi::TagModel *model = testDrivers.second; - - QModelIndexList list = model->match(model->index(0, 0), Qt::DisplayRole, changedTag, 1, Qt::MatchRecursive); - QVERIFY(!list.isEmpty()); - const QModelIndex changedIndex = list.first(); - const QString parentTag = changedIndex.parent().data().toString(); - const int sourceRow = changedIndex.row(); - - QModelIndex newParentIndex; - if (!newParent.isEmpty()) { - list = model->match(model->index(0, 0), Qt::DisplayRole, newParent, 1, Qt::MatchRecursive); - QVERIFY(!list.isEmpty()); - newParentIndex = list.first(); - } - const int destRow = model->rowCount(newParentIndex); + const auto testDrivers = populateModel(serverContent); + const auto serverData = testDrivers.first; + const auto model = testDrivers.second; + + const auto changedIndex = firstMatchedIndex(*model, changedTag); + const auto parentTag = changedIndex.parent().data().toString(); + const auto sourceRow = changedIndex.row(); - FakeTagMovedCommand *moveCommand = new FakeTagMovedCommand(changedTag, parentTag, newParent, serverData); + QModelIndex newParentIndex = firstMatchedIndex(*model, newParent); + const auto destRow = model->rowCount(newParentIndex); + + const auto moveCommand = new FakeTagMovedCommand(changedTag, parentTag, newParent, serverData); m_modelSpy->startSpying(); - serverData->setCommands(QList() << moveCommand); + serverData->setCommands({moveCommand}); const auto parentTagVariant = parentTag.isEmpty() ? QVariant{} : parentTag; const auto newParentVariant = newParent.isEmpty() ? QVariant{} : newParent; const QList expectedSignals { {RowsAboutToBeMoved, sourceRow, sourceRow, parentTagVariant, destRow, newParentVariant, QVariantList{changedTag}}, {RowsMoved, sourceRow, sourceRow, parentTagVariant, destRow, newParentVariant, QVariantList{changedTag}} }; m_modelSpy->setExpectedSignals(expectedSignals); serverData->processNotifications(); // Give the model a change to run the event loop to process the signals. QTest::qWait(0); QVERIFY(m_modelSpy->isEmpty()); } - #include "tagmodeltest.moc" QTEST_MAIN(TagModelTest)