File indexing completed on 2025-01-05 04:59:57
0001 /* 0002 * SPDX-FileCopyrightText: 2019 David Faure <faure@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 0007 #include <testlib/qtest_zanshin.h> 0008 0009 #include <memory> 0010 0011 #include <QMimeData> 0012 0013 #include "utils/datetime.h" 0014 0015 #include "domain/taskqueries.h" 0016 #include "domain/taskrepository.h" 0017 #include "presentation/alltaskspagemodel.h" 0018 #include "presentation/querytreemodelbase.h" 0019 0020 #include "akonadi/akonadiserializerinterface.h" 0021 0022 #include "utils/dependencymanager.h" 0023 #include "integration/dependencies.h" 0024 0025 #include "testlib/fakejob.h" 0026 #include "testlib/akonadifakedata.h" 0027 #include "testlib/gencollection.h" 0028 #include "testlib/gentodo.h" 0029 #include "testlib/testhelpers.h" 0030 0031 using namespace Testlib; 0032 0033 class AllTasksPageModelTest : public QObject 0034 { 0035 Q_OBJECT 0036 private slots: 0037 void cleanup() 0038 { 0039 // The first call to QueryTreeModelBase::data triggers fetchTaskExtraData which creates jobs. 0040 // Wait for these to finish so they don't mess up subsequent tests 0041 TestHelpers::waitForEmptyJobQueue(); 0042 } 0043 0044 void shouldListAllTasksInCentralListModel() 0045 { 0046 // GIVEN 0047 const auto today = Utils::DateTime::currentDate(); 0048 0049 AkonadiFakeData data; 0050 auto deps = data.createDependencies(); 0051 Integration::initializeDefaultDomainDependencies(*deps.get()); 0052 0053 // One top level collection 0054 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0055 0056 // One project 0057 data.createItem(GenTodo().withId(47).withParent(42).withUid("47").withTitle(QStringLiteral("KDE")).asProject()); 0058 0059 // Three tasks 0060 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1")).withStartDate(today.addDays(-10)).withDueDate(today)); 0061 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withParentUid("47").withTitle(QStringLiteral("task2")).withStartDate(today).withDueDate(today.addDays(10))); 0062 data.createItem(GenTodo().withId(44).withParent(42).withUid("44").withTitle(QStringLiteral("task3")).withStartDate(today.addYears(-4)).withDueDate(today.addYears(-3))); 0063 0064 // Two tasks under the task1 0065 data.createItem(GenTodo().withId(45).withParent(42).withUid("45").withParentUid("42").withTitle(QStringLiteral("childTask11"))); 0066 data.createItem(GenTodo().withId(46).withParent(42).withUid("46").withParentUid("42").withTitle(QStringLiteral("childTask12")).withStartDate(today).withDueDate(today)); 0067 0068 auto serializer = deps->create<Akonadi::SerializerInterface>(); 0069 Presentation::AllTasksPageModel pageModel(deps->create<Domain::TaskQueries>(), 0070 deps->create<Domain::TaskRepository>()); 0071 0072 // WHEN 0073 QAbstractItemModel *model = pageModel.centralListModel(); 0074 TestHelpers::waitForEmptyJobQueue(); 0075 0076 // THEN 0077 QCOMPARE(model->rowCount(), 3); 0078 0079 const QModelIndex task1Index = model->index(0, 0); 0080 const QModelIndex task2Index = model->index(1, 0); 0081 const QModelIndex task3Index = model->index(2, 0); 0082 0083 const QModelIndex childTask11Index = model->index(0, 0, task1Index); 0084 const QModelIndex childTask12Index = model->index(1, 0, task1Index); 0085 0086 QCOMPARE(model->rowCount(task1Index), 2); 0087 QCOMPARE(model->rowCount(task2Index), 0); 0088 QCOMPARE(model->rowCount(task3Index), 0); 0089 0090 QVERIFY(childTask11Index.isValid()); 0091 QVERIFY(childTask12Index.isValid()); 0092 QCOMPARE(model->rowCount(childTask11Index), 0); 0093 QCOMPARE(model->rowCount(childTask12Index), 0); 0094 0095 auto task1 = model->data(task1Index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0096 auto task2 = model->data(task2Index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0097 auto task3 = model->data(task3Index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0098 auto childTask11 = model->data(childTask11Index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0099 auto childTask12 = model->data(childTask12Index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0100 0101 TestHelpers::waitForEmptyJobQueue(); 0102 0103 const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable 0104 | Qt::ItemIsEnabled 0105 | Qt::ItemIsEditable 0106 | Qt::ItemIsDragEnabled; 0107 QCOMPARE(model->flags(task1Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0108 QCOMPARE(model->flags(childTask11Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0109 QCOMPARE(model->flags(childTask12Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0110 QCOMPARE(model->flags(task2Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0111 QCOMPARE(model->flags(task3Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0112 0113 QCOMPARE(model->data(task1Index).toString(), task1->title()); 0114 QCOMPARE(model->data(childTask11Index).toString(), childTask11->title()); 0115 QCOMPARE(model->data(childTask12Index).toString(), childTask12->title()); 0116 QCOMPARE(model->data(task2Index).toString(), task2->title()); 0117 QCOMPARE(model->data(task3Index).toString(), task3->title()); 0118 0119 QCOMPARE(model->data(task1Index, Qt::EditRole).toString(), task1->title()); 0120 QCOMPARE(model->data(childTask11Index, Qt::EditRole).toString(), childTask11->title()); 0121 QCOMPARE(model->data(childTask12Index, Qt::EditRole).toString(), childTask12->title()); 0122 QCOMPARE(model->data(task2Index, Qt::EditRole).toString(), task2->title()); 0123 QCOMPARE(model->data(task3Index, Qt::EditRole).toString(), task3->title()); 0124 0125 QVERIFY(model->data(task1Index, Qt::CheckStateRole).isValid()); 0126 QVERIFY(model->data(childTask11Index, Qt::CheckStateRole).isValid()); 0127 QVERIFY(model->data(childTask12Index, Qt::CheckStateRole).isValid()); 0128 QVERIFY(model->data(task2Index, Qt::CheckStateRole).isValid()); 0129 QVERIFY(model->data(task3Index, Qt::CheckStateRole).isValid()); 0130 0131 QCOMPARE(model->data(task1Index, Qt::CheckStateRole).toBool(), false); 0132 QCOMPARE(model->data(childTask11Index, Qt::CheckStateRole).toBool(), false); 0133 QCOMPARE(model->data(childTask12Index, Qt::CheckStateRole).toBool(), false); 0134 QCOMPARE(model->data(task2Index, Qt::CheckStateRole).toBool(), false); 0135 QCOMPARE(model->data(task3Index, Qt::CheckStateRole).toBool(), false); 0136 0137 QVERIFY(model->data(task1Index, Presentation::QueryTreeModelBase::ProjectRole).isValid()); 0138 QVERIFY(model->data(task2Index, Presentation::QueryTreeModelBase::ProjectRole).isValid()); 0139 QCOMPARE(model->data(task1Index, Presentation::QueryTreeModelBase::ProjectRole).toString(), QString()); 0140 QCOMPARE(model->data(task2Index, Presentation::QueryTreeModelBase::ProjectRole).toString(), QString("KDE")); 0141 QCOMPARE(model->data(task1Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), false); 0142 QCOMPARE(model->data(task2Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), false); 0143 QVERIFY(!model->data(childTask11Index, Presentation::QueryTreeModelBase::ProjectRole).isValid()); 0144 QVERIFY(!model->data(childTask12Index, Presentation::QueryTreeModelBase::ProjectRole).isValid()); 0145 QCOMPARE(model->data(childTask11Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), true); 0146 QCOMPARE(model->data(childTask12Index, Presentation::QueryTreeModelBase::IsChildRole).toBool(), true); 0147 0148 // WHEN 0149 QVERIFY(model->setData(task1Index, "newTask1")); 0150 QVERIFY(model->setData(childTask11Index, "newChildTask11")); 0151 QVERIFY(model->setData(task2Index, "newTask2")); 0152 QVERIFY(model->setData(task3Index, "newTask3")); 0153 QVERIFY(model->setData(childTask12Index, "newChildTask12")); 0154 0155 QVERIFY(model->setData(task1Index, Qt::Unchecked, Qt::CheckStateRole)); 0156 QVERIFY(model->setData(childTask11Index, Qt::Unchecked, Qt::CheckStateRole)); 0157 QVERIFY(model->setData(task2Index, Qt::Checked, Qt::CheckStateRole)); 0158 QVERIFY(model->setData(task3Index, Qt::Unchecked, Qt::CheckStateRole)); 0159 QVERIFY(model->setData(childTask12Index, Qt::Checked, Qt::CheckStateRole)); 0160 0161 // THEN 0162 QCOMPARE(task1->title(), QStringLiteral("newTask1")); 0163 QCOMPARE(childTask11->title(), QStringLiteral("newChildTask11")); 0164 QCOMPARE(childTask12->title(), QStringLiteral("newChildTask12")); 0165 QCOMPARE(task2->title(), QStringLiteral("newTask2")); 0166 QCOMPARE(task3->title(), QStringLiteral("newTask3")); 0167 0168 QCOMPARE(task1->isDone(), false); 0169 QCOMPARE(childTask11->isDone(), false); 0170 QCOMPARE(childTask12->isDone(), true); 0171 QCOMPARE(task2->isDone(), true); 0172 QCOMPARE(task3->isDone(), false); 0173 0174 // WHEN 0175 auto mimeData = std::unique_ptr<QMimeData>(model->mimeData(QModelIndexList() << childTask12Index)); 0176 0177 // THEN 0178 QVERIFY(mimeData->hasFormat(QStringLiteral("application/x-zanshin-object"))); 0179 QCOMPARE(mimeData->property("objects").value<Domain::Task::List>(), 0180 Domain::Task::List() << childTask12); 0181 0182 // WHEN 0183 data.createItem(GenTodo().withId(48).withParent(42).withUid("48").withTitle(QStringLiteral("childTask2"))); 0184 auto childTask2 = model->data(model->index(3, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0185 mimeData.reset(new QMimeData); 0186 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0187 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask2)); 0188 model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, childTask11Index); 0189 TestHelpers::waitForEmptyJobQueue(); 0190 0191 // THEN 0192 QCOMPARE(serializer->relatedUidFromItem(data.item(48)), QStringLiteral("45")); 0193 QCOMPARE(model->rowCount(), 3); 0194 QCOMPARE(model->rowCount(childTask11Index), 1); 0195 0196 // WHEN 0197 data.createItem(GenTodo().withId(49).withParent(42).withUid("49").withTitle(QStringLiteral("childTask3"))); 0198 auto childTask3 = model->data(model->index(3, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0199 data.createItem(GenTodo().withId(50).withParent(42).withUid("50").withTitle(QStringLiteral("childTask4"))); 0200 auto childTask4 = model->data(model->index(4, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0201 mimeData.reset(new QMimeData); 0202 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0203 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask3 << childTask4)); 0204 model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, childTask12Index); 0205 TestHelpers::waitForEmptyJobQueue(); 0206 0207 // THEN 0208 QCOMPARE(serializer->relatedUidFromItem(data.item(49)), QStringLiteral("46")); 0209 QCOMPARE(serializer->relatedUidFromItem(data.item(50)), QStringLiteral("46")); 0210 QCOMPARE(model->rowCount(), 3); 0211 QCOMPARE(model->rowCount(childTask12Index), 2); 0212 0213 // WHEN 0214 QVERIFY(!childTask4->startDate().isValid()); 0215 mimeData.reset(new QMimeData); 0216 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0217 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask4)); 0218 model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, QModelIndex()); 0219 TestHelpers::waitForEmptyJobQueue(); 0220 0221 // THEN 0222 QCOMPARE(serializer->relatedUidFromItem(data.item(50)), QString()); 0223 QCOMPARE(model->rowCount(), 4); 0224 QCOMPARE(model->rowCount(childTask12Index), 1); 0225 QCOMPARE(childTask4->startDate(), QDate()); // unlike the workday 0226 } 0227 0228 void shouldAddTasksInAllTasksPage() 0229 { 0230 // GIVEN 0231 AkonadiFakeData data; 0232 auto deps = data.createDependencies(); 0233 Integration::initializeDefaultDomainDependencies(*deps.get()); 0234 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0235 0236 Presentation::AllTasksPageModel pageModel(deps->create<Domain::TaskQueries>(), 0237 deps->create<Domain::TaskRepository>()); 0238 QAbstractItemModel *model = pageModel.centralListModel(); 0239 0240 // WHEN 0241 auto title = QStringLiteral("New task"); 0242 auto createdTask = pageModel.addItem(title); 0243 TestHelpers::waitForEmptyJobQueue(); 0244 0245 // THEN 0246 QVERIFY(createdTask); 0247 QCOMPARE(createdTask->title(), title); 0248 QCOMPARE(createdTask->startDate(), QDate()); // that's one difference with the workday, which would set it to Utils::DateTime::currentDate() 0249 0250 QCOMPARE(model->rowCount(), 1); 0251 auto taskInModel = model->data(model->index(0, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0252 QVERIFY(taskInModel); 0253 QCOMPARE(taskInModel->title(), createdTask->title()); 0254 QCOMPARE(taskInModel->startDate(), createdTask->startDate()); 0255 0256 QCOMPARE(data.items().count(), 1); 0257 } 0258 0259 void shouldAddChildTask() 0260 { 0261 // GIVEN 0262 AkonadiFakeData data; 0263 auto deps = data.createDependencies(); 0264 Integration::initializeDefaultDomainDependencies(*deps.get()); 0265 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0266 0267 // One project 0268 data.createItem(GenTodo().withId(47).withParent(42).withUid("47").withTitle(QStringLiteral("KDE")).asProject()); 0269 0270 // One task 0271 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0272 QCOMPARE(data.items().count(), 2); 0273 0274 Presentation::AllTasksPageModel pageModel(deps->create<Domain::TaskQueries>(), 0275 deps->create<Domain::TaskRepository>()); 0276 QAbstractItemModel *model = pageModel.centralListModel(); 0277 TestHelpers::waitForEmptyJobQueue(); 0278 QCOMPARE(model->rowCount(), 1); 0279 0280 // WHEN 0281 const auto title = QStringLiteral("New task"); 0282 const auto parentIndex = model->index(0, 0); 0283 const auto createdTask = pageModel.addItem(title, parentIndex); 0284 TestHelpers::waitForEmptyJobQueue(); 0285 0286 // THEN 0287 QVERIFY(createdTask); 0288 QCOMPARE(createdTask->title(), title); 0289 QVERIFY(!createdTask->startDate().isValid()); 0290 0291 QCOMPARE(model->rowCount(parentIndex), 1); 0292 auto taskInModel = model->data(model->index(0, 0, parentIndex), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0293 QVERIFY(taskInModel); 0294 QCOMPARE(taskInModel->title(), createdTask->title()); 0295 QCOMPARE(taskInModel->startDate(), createdTask->startDate()); 0296 0297 QCOMPARE(data.items().count(), 3); 0298 } 0299 0300 void shouldDeleteItems() 0301 { 0302 // GIVEN 0303 AkonadiFakeData data; 0304 auto deps = data.createDependencies(); 0305 Integration::initializeDefaultDomainDependencies(*deps.get()); 0306 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0307 0308 // Two tasks 0309 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0310 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0311 QCOMPARE(data.items().count(), 2); 0312 0313 Presentation::AllTasksPageModel pageModel(deps->create<Domain::TaskQueries>(), 0314 deps->create<Domain::TaskRepository>()); 0315 QAbstractItemModel *model = pageModel.centralListModel(); 0316 TestHelpers::waitForEmptyJobQueue(); 0317 QCOMPARE(model->rowCount(), 2); 0318 0319 // WHEN 0320 const QModelIndex index = model->index(1, 0); 0321 QVERIFY(index.isValid()); 0322 pageModel.removeItem(index); 0323 TestHelpers::waitForEmptyJobQueue(); 0324 0325 // THEN 0326 QCOMPARE(model->rowCount(), 1); 0327 QCOMPARE(data.items().count(), 1); 0328 } 0329 0330 void shouldPromoteItem() 0331 { 0332 // GIVEN 0333 AkonadiFakeData data; 0334 auto deps = data.createDependencies(); 0335 Integration::initializeDefaultDomainDependencies(*deps.get()); 0336 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0337 0338 // Two tasks 0339 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0340 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0341 QCOMPARE(data.items().count(), 2); 0342 0343 auto serializer = deps->create<Akonadi::SerializerInterface>(); 0344 0345 QVERIFY(!serializer->isProjectItem(data.items().at(1))); 0346 0347 Presentation::AllTasksPageModel pageModel(deps->create<Domain::TaskQueries>(), 0348 deps->create<Domain::TaskRepository>()); 0349 QAbstractItemModel *model = pageModel.centralListModel(); 0350 TestHelpers::waitForEmptyJobQueue(); 0351 QCOMPARE(model->rowCount(), 2); 0352 0353 // WHEN 0354 const QModelIndex index = model->index(1, 0); 0355 pageModel.promoteItem(index); 0356 TestHelpers::waitForEmptyJobQueue(); 0357 0358 // THEN 0359 QCOMPARE(model->rowCount(), 1); 0360 QCOMPARE(data.items().count(), 2); 0361 QVERIFY(serializer->isProjectItem(data.items().at(1))); 0362 } 0363 }; 0364 0365 ZANSHIN_TEST_MAIN(AllTasksPageModelTest) 0366 0367 #include "alltaskspagemodeltest.moc"