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)