File indexing completed on 2025-01-05 04:59:59
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@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 0014 #include "domain/taskqueries.h" 0015 #include "domain/taskrepository.h" 0016 0017 #include "presentation/inboxpagemodel.h" 0018 #include "presentation/errorhandler.h" 0019 #include "presentation/querytreemodelbase.h" 0020 0021 #include "akonadi/akonadiserializerinterface.h" 0022 0023 #include "utils/dependencymanager.h" 0024 #include "integration/dependencies.h" 0025 0026 #include "testlib/fakejob.h" 0027 #include "testlib/akonadifakedata.h" 0028 #include "testlib/gencollection.h" 0029 #include "testlib/gentodo.h" 0030 #include "testlib/testhelpers.h" 0031 0032 using namespace Testlib; 0033 0034 class FakeErrorHandler : public Presentation::ErrorHandler 0035 { 0036 public: 0037 void doDisplayMessage(const QString &message) override 0038 { 0039 m_message = message; 0040 } 0041 0042 QString m_message; 0043 }; 0044 0045 class InboxPageModelTest : public QObject 0046 { 0047 Q_OBJECT 0048 private slots: 0049 void cleanup() 0050 { 0051 // The first call to QueryTreeModelBase::data triggers fetchTaskExtraData which creates jobs. 0052 // Wait for these to finish so they don't mess up subsequent tests 0053 TestHelpers::waitForEmptyJobQueue(); 0054 } 0055 0056 void shouldListInboxInCentralListModel() 0057 { 0058 // GIVEN 0059 0060 AkonadiFakeData data; 0061 auto deps = data.createDependencies(); 0062 Integration::initializeDefaultDomainDependencies(*deps.get()); 0063 0064 // One top level collection 0065 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0066 0067 // One root task 0068 data.createItem(GenTodo().withId(1).withParent(42).withUid("1").withTitle(QStringLiteral("rootTask"))); 0069 0070 // One task under the root task 0071 data.createItem(GenTodo().withId(2).withParent(42).withUid("2").withParentUid("1").done(true).withTitle(QStringLiteral("childTask"))); 0072 0073 auto serializer = deps->create<Akonadi::SerializerInterface>(); 0074 Presentation::InboxPageModel inbox(deps->create<Domain::TaskQueries>(), 0075 deps->create<Domain::TaskRepository>()); 0076 0077 // WHEN 0078 QAbstractItemModel *model = inbox.centralListModel(); 0079 TestHelpers::waitForEmptyJobQueue(); 0080 0081 // THEN 0082 const QModelIndex rootTaskIndex = model->index(0, 0); 0083 const QModelIndex childTaskIndex = model->index(0, 0, rootTaskIndex); 0084 0085 QCOMPARE(model->rowCount(), 1); 0086 QCOMPARE(model->rowCount(rootTaskIndex), 1); 0087 QCOMPARE(model->rowCount(childTaskIndex), 0); 0088 0089 auto rootTask = model->data(rootTaskIndex, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0090 auto childTask = model->data(childTaskIndex, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0091 0092 const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable 0093 | Qt::ItemIsEnabled 0094 | Qt::ItemIsEditable 0095 | Qt::ItemIsDragEnabled; 0096 QCOMPARE(model->flags(rootTaskIndex), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0097 QCOMPARE(model->flags(childTaskIndex), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); 0098 0099 QCOMPARE(model->data(rootTaskIndex).toString(), rootTask->title()); 0100 QCOMPARE(model->data(childTaskIndex).toString(), childTask->title()); 0101 0102 QCOMPARE(model->data(rootTaskIndex, Qt::EditRole).toString(), rootTask->title()); 0103 QCOMPARE(model->data(childTaskIndex, Qt::EditRole).toString(), childTask->title()); 0104 0105 QVERIFY(model->data(rootTaskIndex, Qt::CheckStateRole).isValid()); 0106 QVERIFY(model->data(childTaskIndex, Qt::CheckStateRole).isValid()); 0107 0108 QCOMPARE(model->data(rootTaskIndex, Qt::CheckStateRole).toBool(), rootTask->isDone()); 0109 QCOMPARE(model->data(childTaskIndex, Qt::CheckStateRole).toBool(), childTask->isDone()); 0110 0111 // WHEN 0112 QVERIFY(model->setData(rootTaskIndex, "newRootTask")); 0113 QVERIFY(model->setData(childTaskIndex, "newChildTask")); 0114 0115 QVERIFY(model->setData(rootTaskIndex, Qt::Checked, Qt::CheckStateRole)); 0116 QVERIFY(model->setData(childTaskIndex, Qt::Unchecked, Qt::CheckStateRole)); 0117 0118 // THEN 0119 QCOMPARE(rootTask->title(), QStringLiteral("newRootTask")); 0120 QCOMPARE(childTask->title(), QStringLiteral("newChildTask")); 0121 0122 QCOMPARE(rootTask->isDone(), true); 0123 QCOMPARE(childTask->isDone(), false); 0124 0125 // WHEN 0126 auto mimeData = std::unique_ptr<QMimeData>(model->mimeData(QModelIndexList() << childTaskIndex)); 0127 0128 // THEN 0129 QVERIFY(mimeData->hasFormat(QStringLiteral("application/x-zanshin-object"))); 0130 QCOMPARE(mimeData->property("objects").value<Domain::Task::List>(), 0131 Domain::Task::List() << childTask); 0132 0133 // WHEN 0134 // - root (1) 0135 // - child (2) 0136 // - grandchild (48), will be dropped onto root 0137 data.createItem(GenTodo().withId(48).withParent(42).withUid("48").withParentUid("2").withTitle(QStringLiteral("childTask2"))); 0138 QCOMPARE(model->rowCount(childTaskIndex), 1); 0139 auto grandChildTask = model->data(model->index(0, 0, childTaskIndex), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0140 QVERIFY(grandChildTask); 0141 mimeData.reset(new QMimeData); 0142 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0143 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << grandChildTask)); 0144 QVERIFY(model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, rootTaskIndex)); 0145 TestHelpers::waitForEmptyJobQueue(); 0146 0147 // THEN 0148 // root (1) 0149 // - child (2) 0150 // - second child (48) 0151 QCOMPARE(serializer->relatedUidFromItem(data.item(48)), QStringLiteral("1")); 0152 QCOMPARE(model->rowCount(), 1); 0153 QCOMPARE(model->rowCount(rootTaskIndex), 2); 0154 QCOMPARE(model->rowCount(childTaskIndex), 0); 0155 0156 // WHEN 0157 // two more toplevel tasks 0158 data.createItem(GenTodo().withId(49).withParent(42).withUid("49").withTitle(QStringLiteral("childTask3"))); 0159 auto task3 = model->data(model->index(1, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0160 QVERIFY(task3); 0161 data.createItem(GenTodo().withId(50).withParent(42).withUid("50").withTitle(QStringLiteral("childTask4"))); 0162 auto task4 = model->data(model->index(2, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0163 QVERIFY(task4); 0164 mimeData.reset(new QMimeData); 0165 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0166 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << task3 << task4)); 0167 QVERIFY(model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, rootTaskIndex)); 0168 TestHelpers::waitForEmptyJobQueue(); 0169 0170 // THEN 0171 // root (1) 0172 // - child (2) 0173 // - second child (48) 0174 // - task3 (49) 0175 // - task4 (50) 0176 0177 QCOMPARE(serializer->relatedUidFromItem(data.item(49)), QStringLiteral("1")); 0178 QCOMPARE(serializer->relatedUidFromItem(data.item(50)), QStringLiteral("1")); 0179 QCOMPARE(model->rowCount(), 1); 0180 QCOMPARE(model->rowCount(rootTaskIndex), 4); 0181 } 0182 0183 void shouldAddTasksInInbox() 0184 { 0185 // GIVEN 0186 AkonadiFakeData data; 0187 auto deps = data.createDependencies(); 0188 Integration::initializeDefaultDomainDependencies(*deps.get()); 0189 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0190 0191 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0192 deps->create<Domain::TaskRepository>()); 0193 QAbstractItemModel *model = pageModel.centralListModel(); 0194 0195 // WHEN 0196 auto title = QStringLiteral("New task"); 0197 auto createdTask = pageModel.addItem(title); 0198 TestHelpers::waitForEmptyJobQueue(); 0199 0200 // THEN 0201 QVERIFY(createdTask); 0202 QCOMPARE(createdTask->title(), title); 0203 QCOMPARE(model->rowCount(), 1); 0204 auto taskInModel = model->data(model->index(0, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0205 QVERIFY(taskInModel); 0206 QCOMPARE(taskInModel->title(), createdTask->title()); 0207 QCOMPARE(taskInModel->startDate(), createdTask->startDate()); 0208 0209 QCOMPARE(data.items().count(), 1); 0210 TestHelpers::waitForEmptyJobQueue(); 0211 } 0212 0213 void shouldAddChildTask() 0214 { 0215 // GIVEN 0216 AkonadiFakeData data; 0217 auto deps = data.createDependencies(); 0218 Integration::initializeDefaultDomainDependencies(*deps.get()); 0219 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0220 0221 // Two tasks 0222 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0223 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0224 QCOMPARE(data.items().count(), 2); 0225 0226 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0227 deps->create<Domain::TaskRepository>()); 0228 QAbstractItemModel *model = pageModel.centralListModel(); 0229 TestHelpers::waitForEmptyJobQueue(); 0230 QCOMPARE(model->rowCount(), 2); 0231 0232 // WHEN 0233 const auto title = QStringLiteral("New task"); 0234 const auto parentIndex = model->index(0, 0); 0235 const auto createdTask = pageModel.addItem(title, parentIndex); 0236 TestHelpers::waitForEmptyJobQueue(); 0237 0238 // THEN 0239 QVERIFY(createdTask); 0240 QCOMPARE(createdTask->title(), title); 0241 0242 QCOMPARE(model->rowCount(parentIndex), 1); 0243 auto taskInModel = model->data(model->index(0, 0, parentIndex), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0244 QVERIFY(taskInModel); 0245 QCOMPARE(taskInModel->title(), createdTask->title()); 0246 QCOMPARE(taskInModel->startDate(), createdTask->startDate()); 0247 0248 QCOMPARE(data.items().count(), 3); 0249 TestHelpers::waitForEmptyJobQueue(); 0250 } 0251 0252 void shouldGetAnErrorMessageWhenAddTaskFailed() 0253 { 0254 // GIVEN 0255 AkonadiFakeData data; 0256 auto deps = data.createDependencies(); 0257 Integration::initializeDefaultDomainDependencies(*deps.get()); 0258 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0259 0260 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0261 deps->create<Domain::TaskRepository>()); 0262 0263 FakeErrorHandler errorHandler; 0264 pageModel.setErrorHandler(&errorHandler); 0265 0266 // WHEN 0267 data.storageBehavior().setCreateNextItemError(1, QStringLiteral("Foo")); 0268 pageModel.addItem(QStringLiteral("New task")); 0269 TestHelpers::waitForEmptyJobQueue(); 0270 0271 // THEN 0272 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add task New task in Inbox: Foo")); 0273 } 0274 0275 void shouldDeleteItems() 0276 { 0277 // GIVEN 0278 AkonadiFakeData data; 0279 auto deps = data.createDependencies(); 0280 Integration::initializeDefaultDomainDependencies(*deps.get()); 0281 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0282 0283 // Two tasks 0284 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0285 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0286 QCOMPARE(data.items().count(), 2); 0287 0288 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0289 deps->create<Domain::TaskRepository>()); 0290 QAbstractItemModel *model = pageModel.centralListModel(); 0291 TestHelpers::waitForEmptyJobQueue(); 0292 QCOMPARE(model->rowCount(), 2); 0293 0294 // WHEN 0295 const QModelIndex index = model->index(1, 0); 0296 QVERIFY(index.isValid()); 0297 pageModel.removeItem(index); 0298 TestHelpers::waitForEmptyJobQueue(); 0299 0300 // THEN 0301 QCOMPARE(model->rowCount(), 1); 0302 QCOMPARE(data.items().count(), 1); 0303 } 0304 0305 void shouldGetAnErrorMessageWhenDeleteItemsFailed() 0306 { 0307 // GIVEN 0308 AkonadiFakeData data; 0309 auto deps = data.createDependencies(); 0310 Integration::initializeDefaultDomainDependencies(*deps.get()); 0311 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0312 0313 // Two tasks 0314 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0315 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0316 QCOMPARE(data.items().count(), 2); 0317 0318 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0319 deps->create<Domain::TaskRepository>()); 0320 QAbstractItemModel *model = pageModel.centralListModel(); 0321 TestHelpers::waitForEmptyJobQueue(); 0322 QCOMPARE(model->rowCount(), 2); 0323 0324 FakeErrorHandler errorHandler; 0325 pageModel.setErrorHandler(&errorHandler); 0326 0327 // WHEN 0328 data.storageBehavior().setDeleteNextItemError(1, QStringLiteral("Error deleting")); 0329 const QModelIndex index = model->index(1, 0); 0330 pageModel.removeItem(index); 0331 TestHelpers::waitForEmptyJobQueue(); 0332 0333 // THEN 0334 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove task task2 from Inbox: Error deleting")); 0335 } 0336 0337 void shouldPromoteItem() 0338 { 0339 // GIVEN 0340 0341 AkonadiFakeData data; 0342 auto deps = data.createDependencies(); 0343 Integration::initializeDefaultDomainDependencies(*deps.get()); 0344 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0345 0346 // Two tasks 0347 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0348 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0349 QCOMPARE(data.items().count(), 2); 0350 0351 auto serializer = deps->create<Akonadi::SerializerInterface>(); 0352 0353 QVERIFY(!serializer->isProjectItem(data.items().at(1))); 0354 0355 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0356 deps->create<Domain::TaskRepository>()); 0357 QAbstractItemModel *model = pageModel.centralListModel(); 0358 TestHelpers::waitForEmptyJobQueue(); 0359 QCOMPARE(model->rowCount(), 2); 0360 0361 // WHEN 0362 const QModelIndex index = model->index(1, 0); 0363 pageModel.promoteItem(index); 0364 TestHelpers::waitForEmptyJobQueue(); 0365 0366 // THEN 0367 QCOMPARE(model->rowCount(), 1); 0368 QCOMPARE(data.items().count(), 2); 0369 QVERIFY(serializer->isProjectItem(data.items().at(1))); 0370 } 0371 0372 void shouldGetAnErrorMessageWhenPromoteItemFailed() 0373 { 0374 // GIVEN 0375 AkonadiFakeData data; 0376 auto deps = data.createDependencies(); 0377 Integration::initializeDefaultDomainDependencies(*deps.get()); 0378 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0379 0380 // Two tasks 0381 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0382 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0383 QCOMPARE(data.items().count(), 2); 0384 0385 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0386 deps->create<Domain::TaskRepository>()); 0387 QAbstractItemModel *model = pageModel.centralListModel(); 0388 TestHelpers::waitForEmptyJobQueue(); 0389 QCOMPARE(model->rowCount(), 2); 0390 0391 FakeErrorHandler errorHandler; 0392 pageModel.setErrorHandler(&errorHandler); 0393 0394 // WHEN 0395 data.storageBehavior().setUpdateNextItemError(44, QStringLiteral("Foo")); 0396 const QModelIndex index = model->index(1, 0); 0397 pageModel.promoteItem(index); 0398 TestHelpers::waitForEmptyJobQueue(); 0399 0400 // THEN 0401 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot promote task task2 to be a project: Foo")); 0402 } 0403 0404 void shouldGetAnErrorMessageWhenUpdateTaskFailed() 0405 { 0406 // GIVEN 0407 AkonadiFakeData data; 0408 auto deps = data.createDependencies(); 0409 Integration::initializeDefaultDomainDependencies(*deps.get()); 0410 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0411 0412 // One task 0413 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("rootTask"))); 0414 0415 auto serializer = deps->create<Akonadi::SerializerInterface>(); 0416 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0417 deps->create<Domain::TaskRepository>()); 0418 QAbstractItemModel *model = pageModel.centralListModel(); 0419 TestHelpers::waitForEmptyJobQueue(); 0420 0421 FakeErrorHandler errorHandler; 0422 pageModel.setErrorHandler(&errorHandler); 0423 0424 const QModelIndex index = model->index(0, 0); 0425 auto rootTask = model->data(index, Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0426 0427 // WHEN 0428 data.storageBehavior().setUpdateNextItemError(1, QStringLiteral("Update error")); 0429 QVERIFY(model->setData(index, "newRootTask")); 0430 TestHelpers::waitForEmptyJobQueue(); 0431 0432 // THEN 0433 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify task rootTask in Inbox: Update error")); 0434 QCOMPARE(rootTask->title(), QStringLiteral("newRootTask")); // Note that the task *did* get updated 0435 QCOMPARE(index.data().toString(), QStringLiteral("newRootTask")); // and therefore the model keeps showing the new value 0436 QCOMPARE(serializer->createTaskFromItem(data.item(42))->title(), QStringLiteral("rootTask")); // but the underlying data wasn't updated 0437 } 0438 0439 void shouldGetAnErrorMessageWhenAssociateTaskFailed() 0440 { 0441 // GIVEN 0442 AkonadiFakeData data; 0443 auto deps = data.createDependencies(); 0444 Integration::initializeDefaultDomainDependencies(*deps.get()); 0445 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0446 0447 // Three tasks 0448 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("task1"))); 0449 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withTitle(QStringLiteral("task2"))); 0450 data.createItem(GenTodo().withId(44).withParent(42).withUid("44").withTitle(QStringLiteral("task3"))); 0451 0452 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0453 deps->create<Domain::TaskRepository>()); 0454 QAbstractItemModel *model = pageModel.centralListModel(); 0455 TestHelpers::waitForEmptyJobQueue(); 0456 QCOMPARE(model->rowCount(), 3); 0457 0458 FakeErrorHandler errorHandler; 0459 pageModel.setErrorHandler(&errorHandler); 0460 const QModelIndex rootTaskIndex = model->index(0, 0); 0461 0462 auto task2 = model->data(model->index(1, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0463 auto task3 = model->data(model->index(2, 0), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0464 0465 // WHEN 0466 data.storageBehavior().setUpdateNextItemError(1, QStringLiteral("Update error")); 0467 0468 auto mimeData = std::make_unique<QMimeData>(); 0469 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0470 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << task2 << task3)); 0471 QVERIFY(model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, rootTaskIndex)); 0472 TestHelpers::waitForEmptyJobQueue(); 0473 0474 // THEN 0475 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move task task2 as sub-task of task1: Update error")); 0476 QCOMPARE(model->rowCount(), 2); // One failed, one succeeded 0477 } 0478 0479 void shouldDeparentWhenNoErrorHappens() 0480 { 0481 // GIVEN 0482 AkonadiFakeData data; 0483 auto deps = data.createDependencies(); 0484 Integration::initializeDefaultDomainDependencies(*deps.get()); 0485 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0486 0487 // One task, top level 0488 data.createItem(GenTodo().withId(42).withParent(42).withUid("42").withTitle(QStringLiteral("topLevelTask"))); 0489 0490 // Two tasks under the top level task 0491 data.createItem(GenTodo().withId(43).withParent(42).withUid("43").withParentUid("42").withTitle(QStringLiteral("childTask")).done()); 0492 data.createItem(GenTodo().withId(44).withParent(42).withUid("44").withParentUid("42").withTitle(QStringLiteral("childTask2"))); 0493 0494 Presentation::InboxPageModel pageModel(deps->create<Domain::TaskQueries>(), 0495 deps->create<Domain::TaskRepository>()); 0496 QAbstractItemModel *model = pageModel.centralListModel(); 0497 TestHelpers::waitForEmptyJobQueue(); 0498 0499 const QModelIndex emptyPartModel = QModelIndex(); // model root, drop on the empty part is equivalent 0500 FakeErrorHandler errorHandler; 0501 pageModel.setErrorHandler(&errorHandler); 0502 0503 const auto topLevelIndex = model->index(0, 0); 0504 QVERIFY(topLevelIndex.isValid()); 0505 const auto childTask = model->data(model->index(0, 0, topLevelIndex), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0506 const auto childTask2 = model->data(model->index(1, 0, topLevelIndex), Presentation::QueryTreeModelBase::ObjectRole).value<Domain::Task::Ptr>(); 0507 0508 // WHEN 0509 data.storageBehavior().setUpdateNextItemError(1, QStringLiteral("Deparent error")); 0510 0511 auto mimeData = std::make_unique<QMimeData>(); 0512 mimeData->setData(QStringLiteral("application/x-zanshin-object"), "object"); 0513 mimeData->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask << childTask2)); // both will be DnD on the empty part 0514 QVERIFY(model->dropMimeData(mimeData.get(), Qt::MoveAction, -1, -1, emptyPartModel)); 0515 TestHelpers::waitForEmptyJobQueue(); 0516 0517 // THEN 0518 QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot deparent task childTask from its parent: Deparent error")); 0519 QCOMPARE(model->rowCount(), 2); // One failed, one succeeded 0520 } 0521 }; 0522 0523 ZANSHIN_TEST_MAIN(InboxPageModelTest) 0524 0525 #include "inboxpagemodeltest.moc"