File indexing completed on 2024-11-10 04:40:15

0001 /*
0002  * SPDX-FileCopyrightText: 2015 Daniel Vrátil <dvratil@redhat.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  *
0006  */
0007 
0008 #include "qtest_akonadi.h"
0009 
0010 #include "fakemonitor.h"
0011 #include "fakeserverdata.h"
0012 #include "fakesession.h"
0013 #include "modelspy.h"
0014 
0015 #include "tagmodel.h"
0016 #include "tagmodel_p.h"
0017 
0018 static const QString serverContent1 = QStringLiteral(
0019     "- T PLAIN                              'Tag 1'     4"
0020     "- - T PLAIN                            'Tag 2'     3"
0021     "- - - T PLAIN                          'Tag 4'     1"
0022     "- - T PLAIN                            'Tag 3'     2"
0023     "- T PLAIN                              'Tag 5'     5");
0024 
0025 class TagModelTest : public QObject
0026 {
0027     Q_OBJECT
0028 private Q_SLOTS:
0029     void initTestCase();
0030     void cleanupTestCase();
0031 
0032     void testInitialFetch();
0033 
0034     void testTagAdded_data();
0035     void testTagAdded();
0036 
0037     void testTagChanged_data();
0038     void testTagChanged();
0039 
0040     void testTagRemoved_data();
0041     void testTagRemoved();
0042 
0043     void testTagMoved_data();
0044     void testTagMoved();
0045 
0046 private:
0047     QPair<FakeServerData *, Akonadi::TagModel *> populateModel(const QString &serverContent)
0048     {
0049         auto const fakeMonitor = new FakeMonitor(this);
0050 
0051         fakeMonitor->setSession(m_fakeSession);
0052         fakeMonitor->setCollectionMonitored(Collection::root());
0053         fakeMonitor->setTypeMonitored(Akonadi::Monitor::Tags);
0054 
0055         auto const model = new TagModel(fakeMonitor, this);
0056 
0057         m_modelSpy = new ModelSpy{model, this};
0058 
0059         auto const serverData = new FakeServerData(model, m_fakeSession, fakeMonitor, this);
0060         serverData->setCommands(FakeJobResponse::interpret(serverData, serverContent));
0061 
0062         // Give the model a chance to populate
0063         QTest::qWait(100);
0064         return qMakePair(serverData, model);
0065     }
0066 
0067 private:
0068     ModelSpy *m_modelSpy = nullptr;
0069     FakeSession *m_fakeSession = nullptr;
0070     QByteArray m_sessionName;
0071 };
0072 
0073 QModelIndex firstMatchedIndex(const QAbstractItemModel &model, const QString &pattern)
0074 {
0075     if (pattern.isEmpty()) {
0076         return {};
0077     }
0078     const auto list = model.match(model.index(0, 0), Qt::DisplayRole, pattern, 1, Qt::MatchRecursive);
0079     Q_ASSERT(!list.isEmpty());
0080     return list.first();
0081 }
0082 
0083 void TagModelTest::initTestCase()
0084 {
0085     m_sessionName = "TagModelTest fake session";
0086     m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately);
0087     m_fakeSession->setAsDefaultSession();
0088 
0089     qRegisterMetaType<QModelIndex>("QModelIndex");
0090 }
0091 
0092 void TagModelTest::cleanupTestCase()
0093 {
0094     delete m_fakeSession;
0095 }
0096 
0097 void TagModelTest::testInitialFetch()
0098 {
0099     auto const fakeMonitor = new FakeMonitor(this);
0100 
0101     fakeMonitor->setSession(m_fakeSession);
0102     fakeMonitor->setCollectionMonitored(Collection::root());
0103     auto const model = new TagModel(fakeMonitor, this);
0104 
0105     auto const serverData = new FakeServerData(model, m_fakeSession, fakeMonitor, this);
0106     const auto initialFetchResponse = FakeJobResponse::interpret(serverData, serverContent1);
0107     serverData->setCommands(initialFetchResponse);
0108 
0109     m_modelSpy = new ModelSpy{model, this};
0110     m_modelSpy->startSpying();
0111 
0112     const QList<ExpectedSignal> expectedSignals{{RowsAboutToBeInserted, 0, 0},
0113                                                 {RowsInserted, 0, 0},
0114                                                 {RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 1")},
0115                                                 {RowsInserted, 0, 0, QStringLiteral("Tag 1")},
0116                                                 {RowsAboutToBeInserted, 1, 1, QStringLiteral("Tag 1")},
0117                                                 {RowsInserted, 1, 1, QStringLiteral("Tag 1")},
0118                                                 {RowsAboutToBeInserted, 0, 0, QStringLiteral("Tag 2")},
0119                                                 {RowsInserted, 0, 0, QStringLiteral("Tag 2")},
0120                                                 {RowsAboutToBeInserted, 1, 1},
0121                                                 {RowsInserted, 1, 1}};
0122     m_modelSpy->setExpectedSignals(expectedSignals);
0123 
0124     // Give the model a chance to run the event loop to process the signals.
0125     QTest::qWait(10);
0126 
0127     // We get all the signals we expected.
0128     QTRY_VERIFY(m_modelSpy->expectedSignals().isEmpty());
0129 
0130     QTest::qWait(10);
0131     // We didn't get signals we didn't expect.
0132     QVERIFY(m_modelSpy->isEmpty());
0133 }
0134 
0135 void TagModelTest::testTagAdded_data()
0136 {
0137     QTest::addColumn<QString>("serverContent");
0138     QTest::addColumn<QString>("addedTag");
0139     QTest::addColumn<QString>("parentTag");
0140 
0141     QTest::newRow("add-tag01") << serverContent1 << "new Tag"
0142                                << "Tag 1";
0143     QTest::newRow("add-tag02") << serverContent1 << "new Tag"
0144                                << "Tag 2";
0145     QTest::newRow("add-tag03") << serverContent1 << "new Tag"
0146                                << "Tag 3";
0147     QTest::newRow("add-tag04") << serverContent1 << "new Tag"
0148                                << "Tag 4";
0149     QTest::newRow("add-tag05") << serverContent1 << "new Tag"
0150                                << "Tag 5";
0151 }
0152 
0153 void TagModelTest::testTagAdded()
0154 {
0155     QFETCH(QString, serverContent);
0156     QFETCH(QString, addedTag);
0157     QFETCH(QString, parentTag);
0158 
0159     const auto testDrivers = populateModel(serverContent);
0160     auto const serverData = testDrivers.first;
0161     auto const model = testDrivers.second;
0162 
0163     const auto parentIndex = firstMatchedIndex(*model, parentTag);
0164     const auto newRow = model->rowCount(parentIndex);
0165 
0166     auto const addCommand = new FakeTagAddedCommand(addedTag, parentTag, serverData);
0167 
0168     m_modelSpy->startSpying();
0169     serverData->setCommands({addCommand});
0170 
0171     const QList<ExpectedSignal> expectedSignals{{RowsAboutToBeInserted, newRow, newRow, parentTag, QVariantList{addedTag}},
0172                                                 {RowsInserted, newRow, newRow, parentTag, QVariantList{addedTag}}};
0173     m_modelSpy->setExpectedSignals(expectedSignals);
0174     serverData->processNotifications();
0175 
0176     // Give the model a change to run the event loop to process the signals.
0177     QTest::qWait(0);
0178 
0179     QVERIFY(m_modelSpy->isEmpty());
0180 }
0181 
0182 void TagModelTest::testTagChanged_data()
0183 {
0184     QTest::addColumn<QString>("serverContent");
0185     QTest::addColumn<QString>("tagName");
0186 
0187     QTest::newRow("change-tag01") << serverContent1 << "Tag 1";
0188     QTest::newRow("change-tag02") << serverContent1 << "Tag 2";
0189     QTest::newRow("change-tag03") << serverContent1 << "Tag 3";
0190     QTest::newRow("change-tag04") << serverContent1 << "Tag 4";
0191     QTest::newRow("change-tag05") << serverContent1 << "Tag 5";
0192 }
0193 
0194 void TagModelTest::testTagChanged()
0195 {
0196     QFETCH(QString, serverContent);
0197     QFETCH(QString, tagName);
0198 
0199     const auto testDrivers = populateModel(serverContent);
0200     auto const serverData = testDrivers.first;
0201     auto const model = testDrivers.second;
0202 
0203     const auto changedIndex = firstMatchedIndex(*model, tagName);
0204     const auto parentTag = changedIndex.parent().data().toString();
0205     const auto changedRow = changedIndex.row();
0206 
0207     auto const changeCommand = new FakeTagChangedCommand(tagName, parentTag, serverData);
0208 
0209     m_modelSpy->startSpying();
0210     serverData->setCommands(QList<FakeAkonadiServerCommand *>() << changeCommand);
0211 
0212     const QList<ExpectedSignal> expectedSignals{{DataChanged, changedRow, changedRow, parentTag, QVariantList{tagName}}};
0213     m_modelSpy->setExpectedSignals(expectedSignals);
0214     serverData->processNotifications();
0215 
0216     // Give the model a change to run the event loop to process the signals.
0217     QTest::qWait(0);
0218 
0219     QVERIFY(m_modelSpy->isEmpty());
0220 }
0221 
0222 void TagModelTest::testTagRemoved_data()
0223 {
0224     QTest::addColumn<QString>("serverContent");
0225     QTest::addColumn<QString>("removedTag");
0226 
0227     QTest::newRow("remove-tag01") << serverContent1 << "Tag 1";
0228     QTest::newRow("remove-tag02") << serverContent1 << "Tag 2";
0229     QTest::newRow("remove-tag03") << serverContent1 << "Tag 3";
0230     QTest::newRow("remove-tag04") << serverContent1 << "Tag 4";
0231     QTest::newRow("remove-tag05") << serverContent1 << "Tag 5";
0232 }
0233 
0234 void TagModelTest::testTagRemoved()
0235 {
0236     QFETCH(QString, serverContent);
0237     QFETCH(QString, removedTag);
0238 
0239     const auto testDrivers = populateModel(serverContent);
0240     auto const serverData = testDrivers.first;
0241     auto const model = testDrivers.second;
0242 
0243     const auto removedIndex = firstMatchedIndex(*model, removedTag);
0244     const auto parentTag = removedIndex.parent().data().toString();
0245     const auto sourceRow = removedIndex.row();
0246 
0247     auto const removeCommand = new FakeTagRemovedCommand(removedTag, parentTag, serverData);
0248 
0249     m_modelSpy->startSpying();
0250     serverData->setCommands({removeCommand});
0251 
0252     const auto removedTagList = QVariantList{removedTag};
0253     const auto parentTagVariant = parentTag.isEmpty() ? QVariant{} : parentTag;
0254     const QList<ExpectedSignal> expectedSignals{ExpectedSignal{RowsAboutToBeRemoved, sourceRow, sourceRow, parentTagVariant, removedTagList},
0255                                                 ExpectedSignal{RowsRemoved, sourceRow, sourceRow, parentTagVariant, removedTagList}};
0256 
0257     m_modelSpy->setExpectedSignals(expectedSignals);
0258     serverData->processNotifications();
0259 
0260     // Give the model a change to run the event loop to process the signals.
0261     QTest::qWait(0);
0262 
0263     QVERIFY(m_modelSpy->isEmpty());
0264 }
0265 
0266 void TagModelTest::testTagMoved_data()
0267 {
0268     QTest::addColumn<QString>("serverContent");
0269     QTest::addColumn<QString>("changedTag");
0270     QTest::addColumn<QString>("newParent");
0271 
0272     QTest::newRow("move-tag01") << serverContent1 << "Tag 1"
0273                                 << "Tag 5";
0274     QTest::newRow("move-tag02") << serverContent1 << "Tag 2"
0275                                 << "Tag 5";
0276     QTest::newRow("move-tag03") << serverContent1 << "Tag 3"
0277                                 << "Tag 4";
0278     QTest::newRow("move-tag04") << serverContent1 << "Tag 4"
0279                                 << "Tag 1";
0280     QTest::newRow("move-tag05") << serverContent1 << "Tag 5"
0281                                 << "Tag 2";
0282     QTest::newRow("move-tag06") << serverContent1 << "Tag 3" << QString();
0283     QTest::newRow("move-tag07") << serverContent1 << "Tag 2" << QString();
0284 }
0285 
0286 void TagModelTest::testTagMoved()
0287 {
0288     QFETCH(QString, serverContent);
0289     QFETCH(QString, changedTag);
0290     QFETCH(QString, newParent);
0291 
0292     const auto testDrivers = populateModel(serverContent);
0293     auto const serverData = testDrivers.first;
0294     auto const model = testDrivers.second;
0295 
0296     const auto changedIndex = firstMatchedIndex(*model, changedTag);
0297     const auto parentTag = changedIndex.parent().data().toString();
0298     const auto sourceRow = changedIndex.row();
0299 
0300     QModelIndex newParentIndex = firstMatchedIndex(*model, newParent);
0301     const auto destRow = model->rowCount(newParentIndex);
0302 
0303     auto const moveCommand = new FakeTagMovedCommand(changedTag, parentTag, newParent, serverData);
0304 
0305     m_modelSpy->startSpying();
0306     serverData->setCommands({moveCommand});
0307 
0308     const auto parentTagVariant = parentTag.isEmpty() ? QVariant{} : parentTag;
0309     const auto newParentVariant = newParent.isEmpty() ? QVariant{} : newParent;
0310     const QList<ExpectedSignal> expectedSignals{
0311         {RowsAboutToBeMoved, sourceRow, sourceRow, parentTagVariant, destRow, newParentVariant, QVariantList{changedTag}},
0312         {RowsMoved, sourceRow, sourceRow, parentTagVariant, destRow, newParentVariant, QVariantList{changedTag}}};
0313 
0314     m_modelSpy->setExpectedSignals(expectedSignals);
0315     serverData->processNotifications();
0316 
0317     // Give the model a change to run the event loop to process the signals.
0318     QTest::qWait(0);
0319 
0320     QVERIFY(m_modelSpy->isEmpty());
0321 }
0322 
0323 #include "tagmodeltest.moc"
0324 
0325 QTEST_MAIN(TagModelTest)