File indexing completed on 2025-01-05 04:59:55
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 <Akonadi/Collection> 0010 #include <Akonadi/Item> 0011 0012 #include "utils/mockobject.h" 0013 0014 #include "testlib/akonadifakedata.h" 0015 #include "testlib/akonadifakejobs.h" 0016 #include "testlib/akonadifakemonitor.h" 0017 #include "testlib/akonadifakestorage.h" 0018 #include "testlib/gencollection.h" 0019 #include "testlib/gentodo.h" 0020 0021 #include "akonadi/akonaditaskrepository.h" 0022 #include "akonadi/akonadiserializer.h" 0023 #include "akonadi/akonadistorageinterface.h" 0024 0025 using namespace mockitopp; 0026 using namespace mockitopp::matcher; 0027 using namespace Testlib; 0028 0029 Q_DECLARE_METATYPE(Testlib::AkonadiFakeItemFetchJob*) 0030 0031 class AkonadiTaskRepositoryTest : public QObject 0032 { 0033 Q_OBJECT 0034 public: 0035 explicit AkonadiTaskRepositoryTest(QObject *parent = nullptr) 0036 : QObject(parent) 0037 { 0038 } 0039 0040 private slots: 0041 void shouldCreateNewItems() 0042 { 0043 // GIVEN 0044 0045 // A default collection for saving 0046 Akonadi::Collection col(42); 0047 0048 // A task and its corresponding item not existing in storage yet 0049 Akonadi::Item item; 0050 Domain::Task::Ptr task(new Domain::Task); 0051 0052 // A mock create job 0053 auto itemCreateJob = new FakeJob(this); 0054 0055 // Storage mock returning the create job 0056 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0057 storageMock(&Akonadi::StorageInterface::defaultCollection).when().thenReturn(col); 0058 storageMock(&Akonadi::StorageInterface::createItem).when(item, col) 0059 .thenReturn(itemCreateJob); 0060 0061 // Serializer mock returning the item for the task 0062 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0063 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0064 0065 // WHEN 0066 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0067 serializerMock.getInstance())); 0068 repository->create(task)->exec(); 0069 0070 // THEN 0071 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0072 QVERIFY(storageMock(&Akonadi::StorageInterface::defaultCollection).when().exactly(1)); 0073 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(item, col).exactly(1)); 0074 } 0075 0076 void shouldCreateNewItemsInFirstWritableCollectionIsNothingInSettings() 0077 { 0078 // GIVEN 0079 0080 // A few collections 0081 auto col1 = Akonadi::Collection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0082 col1.setRights(Akonadi::Collection::ReadOnly); 0083 auto col2 = Akonadi::Collection(GenCollection().withId(43).withRootAsParent().withTaskContent()); 0084 col2.setRights(Akonadi::Collection::CanCreateItem); 0085 auto col3 = Akonadi::Collection(GenCollection().withId(44).withRootAsParent().withTaskContent()); 0086 col3.setRights(Akonadi::Collection::CanCreateItem 0087 | Akonadi::Collection::CanChangeItem 0088 | Akonadi::Collection::CanDeleteItem); 0089 auto collectionFetchJob = new Testlib::AkonadiFakeCollectionFetchJob; 0090 collectionFetchJob->setCollections(Akonadi::Collection::List() << col1 << col2 << col3); 0091 0092 // A task and its corresponding item not existing in storage yet 0093 Akonadi::Item item; 0094 Domain::Task::Ptr task(new Domain::Task); 0095 0096 // A mock create job 0097 auto itemCreateJob = new FakeJob(this); 0098 0099 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0100 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0101 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0102 serializerMock.getInstance())); 0103 0104 // Storage mock returning the create job and with no default collection 0105 storageMock(&Akonadi::StorageInterface::defaultCollection).when().thenReturn(Akonadi::Collection()); 0106 storageMock(&Akonadi::StorageInterface::fetchCollections).when(Akonadi::Collection::root(), 0107 Akonadi::StorageInterface::Recursive, 0108 repository.get()) 0109 .thenReturn(collectionFetchJob); 0110 storageMock(&Akonadi::StorageInterface::createItem).when(item, col3) 0111 .thenReturn(itemCreateJob); 0112 0113 // Serializer mock returning the item for the task 0114 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0115 0116 // WHEN 0117 repository->create(task)->exec(); 0118 0119 // THEN 0120 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0121 QVERIFY(storageMock(&Akonadi::StorageInterface::defaultCollection).when().exactly(1)); 0122 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(item, col3).exactly(1)); 0123 } 0124 0125 void shouldEmitErrorIfNoFallbackCollectionIsFound() 0126 { 0127 // GIVEN 0128 0129 // A few collections 0130 auto col1 = Akonadi::Collection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0131 col1.setRights(Akonadi::Collection::ReadOnly); 0132 auto col2 = Akonadi::Collection(GenCollection().withId(43).withRootAsParent().withTaskContent()); 0133 col2.setRights(Akonadi::Collection::CanCreateItem); 0134 auto col3 = Akonadi::Collection(GenCollection().withId(44).withRootAsParent().withTaskContent()); 0135 col3.setRights(Akonadi::Collection::ReadOnly); 0136 auto collectionFetchJob = new Testlib::AkonadiFakeCollectionFetchJob; 0137 collectionFetchJob->setCollections(Akonadi::Collection::List() << col1 << col2 << col3); 0138 0139 // A task and its corresponding item not existing in storage yet 0140 Akonadi::Item item; 0141 Domain::Task::Ptr task(new Domain::Task); 0142 0143 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0144 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0145 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0146 serializerMock.getInstance())); 0147 0148 // Storage mock returning the create job and with no default collection 0149 storageMock(&Akonadi::StorageInterface::defaultCollection).when().thenReturn(Akonadi::Collection()); 0150 storageMock(&Akonadi::StorageInterface::fetchCollections).when(Akonadi::Collection::root(), 0151 Akonadi::StorageInterface::Recursive, 0152 repository.get()) 0153 .thenReturn(collectionFetchJob); 0154 0155 // Serializer mock returning the item for the task 0156 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0157 0158 // WHEN 0159 auto job = repository->create(task); 0160 job->exec(); 0161 0162 // THEN 0163 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0164 QVERIFY(storageMock(&Akonadi::StorageInterface::defaultCollection).when().exactly(1)); 0165 QVERIFY(job->error()); 0166 QVERIFY(!job->errorText().isEmpty()); 0167 } 0168 0169 void shouldCreateNewChildrenInParentCollection() 0170 { 0171 // GIVEN 0172 0173 // A parent item with a collection 0174 Akonadi::Collection col(42); 0175 Akonadi::Item parentItem(43); 0176 parentItem.setParentCollection(col); 0177 auto parent = Domain::Task::Ptr::create(); 0178 0179 // A task and its corresponding item not existing in storage yet 0180 Akonadi::Item childItem; 0181 auto child = Domain::Task::Ptr::create(); 0182 0183 // A mock create job 0184 auto itemCreateJob = new FakeJob(this); 0185 0186 // Storage mock returning the create job 0187 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0188 storageMock(&Akonadi::StorageInterface::createItem).when(childItem, col) 0189 .thenReturn(itemCreateJob); 0190 0191 // Serializer mock returning the item for the task 0192 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0193 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(parent).thenReturn(parentItem); 0194 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 0195 serializerMock(&Akonadi::SerializerInterface::updateItemParent).when(childItem, parent).thenReturn(); 0196 0197 // WHEN 0198 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0199 serializerMock.getInstance())); 0200 repository->createChild(child, parent)->exec(); 0201 0202 // THEN 0203 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(parent).exactly(1)); 0204 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1)); 0205 QVERIFY(serializerMock(&Akonadi::SerializerInterface::updateItemParent).when(childItem, parent).exactly(1)); 0206 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(childItem, col).exactly(1)); 0207 } 0208 0209 void shouldCreateNewItemsInProjectCollection() 0210 { 0211 // GIVEN 0212 0213 // A project item with a collection 0214 Akonadi::Collection col(42); 0215 Akonadi::Item projectItem(43); 0216 projectItem.setParentCollection(col); 0217 auto project = Domain::Project::Ptr::create(); 0218 0219 // A task and its corresponding item not existing in storage yet 0220 Akonadi::Item taskItem; 0221 auto task = Domain::Task::Ptr::create(); 0222 0223 // A mock create job 0224 auto itemCreateJob = new FakeJob(this); 0225 0226 // Storage mock returning the create job 0227 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0228 storageMock(&Akonadi::StorageInterface::createItem).when(taskItem, col) 0229 .thenReturn(itemCreateJob); 0230 0231 // Serializer mock returning the item for the task 0232 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0233 serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(projectItem); 0234 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(taskItem); 0235 serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(taskItem, project).thenReturn(); 0236 0237 // WHEN 0238 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0239 serializerMock.getInstance())); 0240 repository->createInProject(task, project)->exec(); 0241 0242 // THEN 0243 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).exactly(1)); 0244 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0245 QVERIFY(serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(taskItem, project).exactly(1)); 0246 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(taskItem, col).exactly(1)); 0247 } 0248 0249 void shouldCreateNewItemsInContext() 0250 { 0251 // GIVEN 0252 // a context item 0253 Akonadi::Item contextItem; 0254 contextItem.setId(42); 0255 0256 // the context related to the item 0257 auto context = Domain::Context::Ptr::create(); 0258 0259 // a default collection 0260 Akonadi::Collection defaultCollection(42); 0261 0262 // A task and its corresponding item not existing in storage yet 0263 Akonadi::Item taskItem; 0264 auto task = Domain::Task::Ptr::create(); 0265 0266 // A mock create job 0267 auto itemCreateJob = new FakeJob(this); 0268 0269 // serializer mock returning the item for the task 0270 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0271 0272 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(taskItem); 0273 serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, taskItem).thenReturn(); 0274 0275 // Storage mock returning the create job 0276 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0277 0278 storageMock(&Akonadi::StorageInterface::defaultCollection).when().thenReturn(defaultCollection); 0279 storageMock(&Akonadi::StorageInterface::createItem).when(taskItem, defaultCollection).thenReturn(itemCreateJob); 0280 0281 // WHEN 0282 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0283 serializerMock.getInstance())); 0284 0285 repository->createInContext(task, context)->exec(); 0286 0287 // THEN 0288 0289 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0290 QVERIFY(serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, taskItem).exactly(1)); 0291 0292 QVERIFY(storageMock(&Akonadi::StorageInterface::defaultCollection).when().exactly(1)); 0293 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(taskItem, defaultCollection).exactly(1)); 0294 } 0295 0296 void shouldUpdateExistingItems() 0297 { 0298 // GIVEN 0299 0300 // A default collection for saving 0301 Akonadi::Collection col(42); 0302 0303 // A task and its corresponding item already existing in storage 0304 Akonadi::Item item(42); 0305 Domain::Task::Ptr task(new Domain::Task); 0306 0307 // A mock create job 0308 auto itemModifyJob = new FakeJob(this); 0309 0310 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0311 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0312 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0313 serializerMock.getInstance())); 0314 0315 // Storage mock returning the create job 0316 storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()) 0317 .thenReturn(itemModifyJob); 0318 0319 // Serializer mock returning the item for the task 0320 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0321 0322 // WHEN 0323 repository->update(task)->exec(); 0324 0325 // THEN 0326 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0327 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()).exactly(1)); 0328 } 0329 0330 void shouldRemoveATask_data() 0331 { 0332 QTest::addColumn<Akonadi::Item>("item"); 0333 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob1"); 0334 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob2"); 0335 QTest::addColumn<Akonadi::Item::List>("list"); 0336 QTest::addColumn<bool>("itemFetchJobSucceeded"); 0337 QTest::addColumn<bool>("collectionItemsFetchJobSucceeded"); 0338 0339 Akonadi::Collection col(40); 0340 0341 Akonadi::Item item(42); 0342 item.setParentCollection(col); 0343 Akonadi::Item item2(43); 0344 0345 auto itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0346 itemFetchJob1->setItems(Akonadi::Item::List() << item); 0347 auto itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0348 0349 Akonadi::Item::List list; 0350 0351 QTest::newRow("nominal case") << item << itemFetchJob1 << itemFetchJob2 << list << true << true; 0352 0353 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0354 itemFetchJob1->setExpectedError(KJob::KilledJobError); 0355 QTest::newRow("item job error with empty list") << item << itemFetchJob1 << itemFetchJob2 << list << false << false; 0356 0357 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0358 itemFetchJob1->setExpectedError(KJob::KilledJobError); 0359 itemFetchJob1->setItems(Akonadi::Item::List() << item); 0360 QTest::newRow("item job error with item") << item << itemFetchJob1 << itemFetchJob2 << list << false << false; 0361 0362 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0363 itemFetchJob1->setItems(Akonadi::Item::List() << item); 0364 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0365 itemFetchJob2->setExpectedError(KJob::KilledJobError); 0366 QTest::newRow("items job error with empty list") << item << itemFetchJob1 << itemFetchJob2 << list << true << false; 0367 0368 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0369 itemFetchJob1->setItems(Akonadi::Item::List() << item); 0370 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0371 list << item2; 0372 itemFetchJob2->setItems(list); 0373 QTest::newRow("remove item and his child") << item << itemFetchJob1 << itemFetchJob2 << list << true << true; 0374 } 0375 0376 void shouldRemoveATask() 0377 { 0378 // GIVEN 0379 QFETCH(Akonadi::Item, item); 0380 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob1); 0381 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob2); 0382 QFETCH(Akonadi::Item::List, list); 0383 QFETCH(bool, itemFetchJobSucceeded); 0384 QFETCH(bool, collectionItemsFetchJobSucceeded); 0385 0386 Domain::Task::Ptr task(new Domain::Task); 0387 0388 Akonadi::Item::List removedList; 0389 removedList << list << item; 0390 0391 // A mock delete job 0392 auto itemDeleteJob = new FakeJob(this); 0393 0394 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0395 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0396 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0397 serializerMock.getInstance())); 0398 0399 // Storage mock returning the delete job 0400 storageMock(&Akonadi::StorageInterface::fetchItem).when(item, repository.get()) 0401 .thenReturn(itemFetchJob1); 0402 storageMock(&Akonadi::StorageInterface::fetchItems).when(item.parentCollection(), repository.get()) 0403 .thenReturn(itemFetchJob2); 0404 storageMock(&Akonadi::StorageInterface::removeItems).when(removedList, repository.get()) 0405 .thenReturn(itemDeleteJob); 0406 0407 // Serializer mock returning the item for the task 0408 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0409 serializerMock(&Akonadi::SerializerInterface::filterDescendantItems).when(list, item).thenReturn(list); 0410 0411 // WHEN 0412 repository->remove(task)->exec(); 0413 0414 // THEN 0415 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0416 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(item, repository.get()).exactly(1)); 0417 if (itemFetchJobSucceeded) { 0418 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItems).when(item.parentCollection(), repository.get()).exactly(1)); 0419 if (collectionItemsFetchJobSucceeded) { 0420 QVERIFY(storageMock(&Akonadi::StorageInterface::removeItems).when(removedList, repository.get()).exactly(1)); 0421 } 0422 } 0423 } 0424 0425 void shouldPromoteTaskToProject() 0426 { 0427 // GIVEN 0428 0429 // A default collection for saving 0430 Akonadi::Collection col(42); 0431 0432 // A task and its corresponding item already existing in storage 0433 Akonadi::Item item(42); 0434 Domain::Task::Ptr task(new Domain::Task); 0435 0436 // A mock fetch job 0437 auto itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 0438 itemFetchJob->setItems(Akonadi::Item::List() << item); 0439 0440 // A mock modify job 0441 auto itemModifyJob = new FakeJob(this); 0442 0443 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0444 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0445 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0446 serializerMock.getInstance())); 0447 0448 // Serializer mock returning the item for the task and transforming it into a project 0449 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(item); 0450 serializerMock(&Akonadi::SerializerInterface::promoteItemToProject).when(item).thenReturn(); 0451 0452 // Storage mock returning the modify job 0453 storageMock(&Akonadi::StorageInterface::fetchItem).when(item, repository.get()) 0454 .thenReturn(itemFetchJob); 0455 storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()) 0456 .thenReturn(itemModifyJob); 0457 0458 // WHEN 0459 repository->promoteToProject(task)->exec(); 0460 0461 // THEN 0462 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); 0463 QVERIFY(serializerMock(&Akonadi::SerializerInterface::promoteItemToProject).when(item).exactly(1)); 0464 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(item, repository.get()).exactly(1)); 0465 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()).exactly(1)); 0466 } 0467 0468 void shouldAssociateATaskToAnother_data() 0469 { 0470 QTest::addColumn<Akonadi::Item>("childItem"); 0471 QTest::addColumn<Akonadi::Item>("parentItem"); 0472 QTest::addColumn<Domain::Task::Ptr>("child"); 0473 QTest::addColumn<Domain::Task::Ptr>("parent"); 0474 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob1"); 0475 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob2"); 0476 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob3"); 0477 QTest::addColumn<bool>("execJob"); 0478 QTest::addColumn<bool>("execParentJob"); 0479 QTest::addColumn<Akonadi::Item::List>("list"); 0480 0481 Akonadi::Collection col(40); 0482 0483 Akonadi::Item childItem(42); 0484 childItem.setParentCollection(col); 0485 Domain::Task::Ptr child(new Domain::Task); 0486 0487 Akonadi::Item parentItem(41); 0488 parentItem.setParentCollection(col); 0489 Domain::Task::Ptr parent(new Domain::Task); 0490 0491 auto itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0492 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0493 auto itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0494 itemFetchJob2->setItems(Akonadi::Item::List() << childItem << parentItem); 0495 auto itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 0496 0497 Akonadi::Item::List list; 0498 0499 QTest::newRow("nominal case") << childItem << parentItem << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list; 0500 0501 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0502 itemFetchJob1->setExpectedError(KJob::KilledJobError); 0503 QTest::newRow("child job error with empty list") << childItem << parentItem << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list; 0504 0505 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0506 itemFetchJob1->setExpectedError(KJob::KilledJobError); 0507 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0508 QTest::newRow("child job error with item") << childItem << parentItem << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list; 0509 0510 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0511 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0512 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0513 itemFetchJob2->setExpectedError(KJob::KilledJobError); 0514 QTest::newRow("parent job error with empty list") << childItem << parentItem << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list; 0515 0516 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0517 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0518 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0519 itemFetchJob2->setExpectedError(KJob::KilledJobError); 0520 itemFetchJob2->setItems(Akonadi::Item::List() << childItem << parentItem); 0521 QTest::newRow("parent job error with item") << childItem << parentItem << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list; 0522 0523 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0524 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0525 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0526 Akonadi::Collection col2(39); 0527 Akonadi::Item parentItem2(41); 0528 parentItem2.setParentCollection(col2); 0529 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2); 0530 itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 0531 QTest::newRow("update and move item") << childItem << parentItem2 << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list; 0532 0533 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 0534 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 0535 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 0536 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2); 0537 itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 0538 Akonadi::Item childItem2(43); 0539 Akonadi::Item::List list2; 0540 list2 << childItem2; 0541 itemFetchJob3->setItems(list2); 0542 QTest::newRow("update and move item and his child") << childItem << parentItem2 << child << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list2; 0543 } 0544 0545 void shouldAssociateATaskToAnother() 0546 { 0547 // GIVEN 0548 QFETCH(Akonadi::Item, childItem); 0549 QFETCH(Akonadi::Item, parentItem); 0550 QFETCH(Domain::Task::Ptr, child); 0551 QFETCH(Domain::Task::Ptr, parent); 0552 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob1); 0553 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob2); 0554 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob3); 0555 QFETCH(bool, execJob); 0556 QFETCH(bool, execParentJob); 0557 QFETCH(Akonadi::Item::List, list); 0558 0559 // A mock create job 0560 auto itemModifyJob = new FakeJob(this); 0561 auto transactionJob = new FakeJob(this); 0562 auto itemsMoveJob = new FakeJob(this); 0563 0564 Akonadi::Item::List movedList; 0565 movedList << childItem << list; 0566 0567 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0568 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0569 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0570 serializerMock.getInstance())); 0571 0572 // Storage mock returning the create job 0573 storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()) 0574 .thenReturn(itemFetchJob1); 0575 storageMock(&Akonadi::StorageInterface::fetchItems).when(parentItem.parentCollection(), repository.get()) 0576 .thenReturn(itemFetchJob2); 0577 if (parentItem.parentCollection().id() != childItem.parentCollection().id()) { 0578 storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get()) 0579 .thenReturn(itemFetchJob3); 0580 storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob); 0581 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob) 0582 .thenReturn(itemModifyJob); 0583 storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob) 0584 .thenReturn(itemsMoveJob); 0585 } else { 0586 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()) 0587 .thenReturn(itemModifyJob); 0588 } 0589 0590 // Serializer mock returning the item for the task 0591 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 0592 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(parent).thenReturn(parentItem); 0593 serializerMock(&Akonadi::SerializerInterface::createTaskFromItem).when(childItem).thenReturn(child); 0594 serializerMock(&Akonadi::SerializerInterface::createTaskFromItem).when(parentItem).thenReturn(parent); 0595 serializerMock(&Akonadi::SerializerInterface::updateItemParent).when(childItem, parent).thenReturn(); 0596 serializerMock(&Akonadi::SerializerInterface::itemUid).when(parentItem).thenReturn(QStringLiteral("parent")); 0597 serializerMock(&Akonadi::SerializerInterface::itemUid).when(childItem).thenReturn(QStringLiteral("child")); 0598 serializerMock(&Akonadi::SerializerInterface::relatedUidFromItem).when(parentItem).thenReturn(QString()); 0599 serializerMock(&Akonadi::SerializerInterface::relatedUidFromItem).when(childItem).thenReturn(QString()); 0600 if (execParentJob) 0601 serializerMock(&Akonadi::SerializerInterface::filterDescendantItems).when(list, childItem).thenReturn(list); 0602 0603 // WHEN 0604 auto associateJob = repository->associate(parent, child); 0605 if (execJob) 0606 associateJob->exec(); 0607 0608 0609 // THEN 0610 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1)); 0611 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1)); 0612 if (execJob) { 0613 QVERIFY(serializerMock(&Akonadi::SerializerInterface::updateItemParent).when(childItem, parent).exactly(1)); 0614 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(parent).exactly(1)); 0615 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItems).when(parentItem.parentCollection(), repository.get()).exactly(1)); 0616 if (execParentJob) { 0617 if (parentItem.parentCollection().id() == childItem.parentCollection().id()) 0618 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1)); 0619 else { 0620 //QVERIFY(serializerMock(&Akonadi::SerializerInterface::filterDescendantItems).when(list, childItem).exactly(1)); 0621 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get()).exactly(1)); 0622 QVERIFY(storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob).exactly(1)); 0623 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob).exactly(1)); 0624 QVERIFY(storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob).exactly(1)); 0625 } 0626 } 0627 } 0628 } 0629 0630 void shouldPreventCyclesDuringAssociation() 0631 { 0632 // GIVEN 0633 AkonadiFakeData data; 0634 0635 // One top level collection 0636 data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent()); 0637 0638 // Three tasks in the collection (one being child of the second one) 0639 data.createItem(GenTodo().withId(42).withParent(42) 0640 .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))); 0641 data.createItem(GenTodo().withId(43).withParent(42) 0642 .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")) 0643 .withParentUid(QStringLiteral("uid-42"))); 0644 data.createItem(GenTodo().withId(44).withParent(42) 0645 .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")) 0646 .withParentUid(QStringLiteral("uid-43"))); 0647 0648 auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer); 0649 auto task42 = serializer->createTaskFromItem(data.item(42)); 0650 auto task44 = serializer->createTaskFromItem(data.item(44)); 0651 0652 auto monitor = Akonadi::MonitorInterface::Ptr(data.createMonitor()); 0653 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(Akonadi::StorageInterface::Ptr(data.createStorage()), 0654 serializer)); 0655 QSignalSpy spy(monitor.data(), &Akonadi::MonitorInterface::itemChanged); 0656 0657 // WHEN 0658 auto job = repository->associate(task44, task42); 0659 QVERIFY(!job->exec()); 0660 0661 // THEN 0662 QVERIFY(spy.isEmpty()); 0663 QVERIFY(job->error() != KJob::NoError); 0664 QVERIFY(!job->errorText().isEmpty()); 0665 } 0666 0667 void shouldDissociateATaskFromItsParent_data() 0668 { 0669 QTest::addColumn<Domain::Task::Ptr>("child"); 0670 QTest::addColumn<Akonadi::Item>("childItem"); 0671 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob"); 0672 QTest::addColumn<bool>("childJobFailed"); 0673 0674 Domain::Task::Ptr child(new Domain::Task); 0675 Akonadi::Item childItem(42); 0676 0677 auto itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 0678 itemFetchJob->setItems(Akonadi::Item::List() << childItem); 0679 0680 QTest::newRow("nominal case") << child << childItem << itemFetchJob << false; 0681 0682 itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 0683 itemFetchJob->setExpectedError(KJob::KilledJobError); 0684 QTest::newRow("child job error with empty list") << child << childItem << itemFetchJob << true; 0685 0686 itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 0687 itemFetchJob->setExpectedError(KJob::KilledJobError); 0688 itemFetchJob->setItems(Akonadi::Item::List() << childItem); 0689 QTest::newRow("child job error with item") << child << childItem << itemFetchJob << true; 0690 } 0691 0692 void shouldDissociateATaskFromItsParent() 0693 { 0694 // GIVEN 0695 QFETCH(Domain::Task::Ptr, child); 0696 QFETCH(Akonadi::Item, childItem); 0697 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob); 0698 QFETCH(bool, childJobFailed); 0699 0700 auto itemModifyJob = new FakeJob(this); 0701 0702 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0703 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0704 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0705 serializerMock.getInstance())); 0706 0707 // Storage mock returning the delete job 0708 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()) 0709 .thenReturn(itemModifyJob); 0710 storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()) 0711 .thenReturn(itemFetchJob); 0712 0713 // Serializer mock returning the item for the task 0714 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 0715 serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).thenReturn(); 0716 0717 // WHEN 0718 repository->dissociate(child)->exec(); 0719 0720 // THEN 0721 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1)); 0722 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1)); 0723 if (!childJobFailed) { 0724 QVERIFY(serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).exactly(1));; 0725 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1)); 0726 } 0727 } 0728 0729 void shouldDissociateAllLinksOfTask_data() 0730 { 0731 shouldDissociateATaskFromItsParent_data(); 0732 } 0733 0734 void shouldDissociateAllLinksOfTask() 0735 { 0736 // GIVEN 0737 QFETCH(Domain::Task::Ptr, child); 0738 QFETCH(Akonadi::Item, childItem); 0739 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob); 0740 QFETCH(bool, childJobFailed); 0741 0742 auto itemModifyJob = new FakeJob(this); 0743 0744 Utils::MockObject<Akonadi::StorageInterface> storageMock; 0745 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 0746 QScopedPointer<Akonadi::TaskRepository> repository(new Akonadi::TaskRepository(storageMock.getInstance(), 0747 serializerMock.getInstance())); 0748 0749 // Storage mock returning the delete job 0750 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()) 0751 .thenReturn(itemModifyJob); 0752 storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()) 0753 .thenReturn(itemFetchJob); 0754 0755 // Serializer mock returning the item for the task 0756 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 0757 serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).thenReturn(); 0758 serializerMock(&Akonadi::SerializerInterface::clearItem).when(any<Akonadi::Item*>()).thenReturn(); 0759 0760 // WHEN 0761 repository->dissociateAll(child)->exec(); 0762 0763 // THEN 0764 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1)); 0765 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1)); 0766 if (!childJobFailed) { 0767 QVERIFY(serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).exactly(1)); 0768 QVERIFY(serializerMock(&Akonadi::SerializerInterface::clearItem).when(any<Akonadi::Item*>()).exactly(1)); 0769 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1)); 0770 } 0771 0772 // Give a chance to job to delete themselves 0773 // in case of an error (since they use deleteLater() internally) 0774 QTest::qWait(10); 0775 } 0776 }; 0777 0778 ZANSHIN_TEST_MAIN(AkonadiTaskRepositoryTest) 0779 0780 #include "akonaditaskrepositorytest.moc"