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"