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/akonadicachingstorage.h"
0010 #include "akonadi/akonaditaskqueries.h"
0011 #include "akonadi/akonadiserializer.h"
0012 #include "akonadi/akonadiitemfetchjobinterface.h"
0013 
0014 #include "testlib/akonadifakedata.h"
0015 #include "testlib/gencollection.h"
0016 #include "testlib/gentodo.h"
0017 #include "testlib/testhelpers.h"
0018 
0019 #include "utils/datetime.h"
0020 
0021 using namespace Testlib;
0022 
0023 class AkonadiTaskQueriesTest : public QObject
0024 {
0025     Q_OBJECT
0026 private:
0027     Akonadi::StorageInterface::Ptr createCachingStorage(AkonadiFakeData &data, const Akonadi::Cache::Ptr &cache)
0028     {
0029         auto storage = Akonadi::StorageInterface::Ptr(data.createStorage());
0030         return Akonadi::StorageInterface::Ptr(new Akonadi::CachingStorage(cache, storage));
0031     }
0032 
0033 private slots:
0034     void shouldLookInAllReportedForAllTasks()
0035     {
0036         // GIVEN
0037         AkonadiFakeData data;
0038 
0039         // Two top level collections
0040         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0041         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
0042 
0043         // One task in the first collection
0044         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0045 
0046         // Two tasks in the second collection
0047         data.createItem(GenTodo().withId(43).withParent(43).withTitle(QStringLiteral("43")));
0048         data.createItem(GenTodo().withId(44).withParent(43).withTitle(QStringLiteral("44")));
0049 
0050         // WHEN
0051         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0052                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0053                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0054                                                                              Akonadi::Cache::Ptr()));
0055         auto result = queries->findAll();
0056         result->data();
0057         result = queries->findAll(); // Should not cause any problem or wrong data
0058 
0059         // THEN
0060         QVERIFY(result->data().isEmpty());
0061         TestHelpers::waitForEmptyJobQueue();
0062 
0063         QCOMPARE(result->data().size(), 3);
0064         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0065         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
0066         QCOMPARE(result->data().at(2)->title(), QStringLiteral("44"));
0067     }
0068 
0069     void shouldIgnoreItemsWhichAreNotTasks()
0070     {
0071         // GIVEN
0072         AkonadiFakeData data;
0073 
0074         // Two top level collections
0075         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0076 
0077         // Two items in the collection
0078         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0079         // One of them is not a task
0080         auto item = Akonadi::Item(43);
0081         item.setPayloadFromData("FooBar");
0082         item.setParentCollection(Akonadi::Collection(42));
0083         data.createItem(item);
0084 
0085         // WHEN
0086         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0087                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0088                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0089                                                                              Akonadi::Cache::Ptr()));
0090         auto result = queries->findAll();
0091 
0092         // THEN
0093         QVERIFY(result->data().isEmpty());
0094         TestHelpers::waitForEmptyJobQueue();
0095 
0096         QCOMPARE(result->data().size(), 1);
0097         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0098     }
0099 
0100     void shouldReactToItemAddsForTasksOnly()
0101     {
0102         // GIVEN
0103         AkonadiFakeData data;
0104 
0105         // One empty collection
0106         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0107 
0108         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0109                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0110                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0111                                                                              Akonadi::Cache::Ptr()));
0112         auto result = queries->findAll();
0113         TestHelpers::waitForEmptyJobQueue();
0114         QVERIFY(result->data().isEmpty());
0115 
0116         // WHEN
0117         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0118         auto item = Akonadi::Item(43);
0119         item.setPayloadFromData("FooBar");
0120         item.setParentCollection(Akonadi::Collection(42));
0121         data.createItem(item);
0122 
0123         // THEN
0124         QCOMPARE(result->data().size(), 1);
0125         QCOMPARE(result->data().first()->title(), QStringLiteral("42"));
0126     }
0127 
0128     void shouldReactToItemRemovesForAllTasks()
0129     {
0130         // GIVEN
0131         AkonadiFakeData data;
0132 
0133         // One top level collection
0134         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0135 
0136         // Three task in the collection
0137         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0138         data.createItem(GenTodo().withId(43).withParent(42).withTitle(QStringLiteral("43")));
0139         data.createItem(GenTodo().withId(44).withParent(42).withTitle(QStringLiteral("44")));
0140 
0141         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0142                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0143                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0144                                                                              Akonadi::Cache::Ptr()));
0145         auto result = queries->findAll();
0146         TestHelpers::waitForEmptyJobQueue();
0147         QCOMPARE(result->data().size(), 3);
0148 
0149         // WHEN
0150         data.removeItem(Akonadi::Item(43));
0151 
0152         // THEN
0153         QCOMPARE(result->data().size(), 2);
0154         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0155         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
0156     }
0157 
0158     void shouldReactToItemChangesForAllTasks()
0159     {
0160         // GIVEN
0161         AkonadiFakeData data;
0162 
0163         // One top level collection
0164         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0165 
0166         // Three task in the collection
0167         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0168         data.createItem(GenTodo().withId(43).withParent(42).withTitle(QStringLiteral("43")));
0169         data.createItem(GenTodo().withId(44).withParent(42).withTitle(QStringLiteral("44")));
0170 
0171         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0172                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0173                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0174                                                                              Akonadi::Cache::Ptr()));
0175         auto result = queries->findAll();
0176         // Even though the pointer didn't change it's convenient to user if we call
0177         // the replace handlers
0178         bool replaceHandlerCalled = false;
0179         result->addPostReplaceHandler([&replaceHandlerCalled](const Domain::Task::Ptr &, int) {
0180                                           replaceHandlerCalled = true;
0181                                       });
0182         TestHelpers::waitForEmptyJobQueue();
0183         QCOMPARE(result->data().size(), 3);
0184 
0185         // WHEN
0186         data.modifyItem(GenTodo(data.item(43)).withTitle(QStringLiteral("43bis")));
0187 
0188         // THEN
0189         QCOMPARE(result->data().size(), 3);
0190         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0191         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43bis"));
0192         QCOMPARE(result->data().at(2)->title(), QStringLiteral("44"));
0193         QVERIFY(replaceHandlerCalled);
0194     }
0195 
0196     void shouldLookInAllChildrenReportedForAllChildrenTask()
0197     {
0198         // GIVEN
0199         AkonadiFakeData data;
0200 
0201         // One top level collection
0202         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0203 
0204         // Three tasks in the collection (two being children of the first one)
0205         data.createItem(GenTodo().withId(42).withParent(42)
0206                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0207         data.createItem(GenTodo().withId(43).withParent(42)
0208                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0209                                  .withParentUid(QStringLiteral("uid-42")));
0210         data.createItem(GenTodo().withId(44).withParent(42)
0211                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0212                                  .withParentUid(QStringLiteral("uid-42")));
0213 
0214         // WHEN
0215         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0216         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0217                                                                              serializer,
0218                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0219                                                                              Akonadi::Cache::Ptr()));
0220         auto task = serializer->createTaskFromItem(data.item(42));
0221         auto result = queries->findChildren(task);
0222         result->data();
0223         result = queries->findChildren(task); // Should not cause any problem or wrong data
0224 
0225         // THEN
0226         QVERIFY(result->data().isEmpty());
0227         TestHelpers::waitForEmptyJobQueue();
0228 
0229         QCOMPARE(result->data().size(), 2);
0230         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
0231         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
0232 
0233         // Should not change nothing
0234         result = queries->findChildren(task);
0235 
0236         QCOMPARE(result->data().size(), 2);
0237         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
0238         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
0239     }
0240 
0241     void shouldNotCrashWhenWeAskAgainTheSameChildrenList()
0242     {
0243         // GIVEN
0244         AkonadiFakeData data;
0245 
0246         // One top level collection
0247         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0248 
0249         // One task in the collection
0250         data.createItem(GenTodo().withId(42).withParent(42)
0251                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0252 
0253         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0254         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0255                                                                              serializer,
0256                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0257                                                                              Akonadi::Cache::Ptr()));
0258         auto task = serializer->createTaskFromItem(data.item(42));
0259 
0260         // The bug we're trying to hit here is the following:
0261         //  - when findChildren is called the first time a provider is created internally
0262         //  - result is deleted at the end of the loop, no one holds the provider with
0263         //    a strong reference anymore so it is deleted as well
0264         //  - when findChildren is called the second time, there's a risk of a dangling
0265         //    pointer if the recycling of providers is wrongly implemented which can lead
0266         //    to a crash, if it is properly done no crash will occur
0267         for (int i = 0; i < 2; i++) {
0268             // WHEN * 2
0269             auto result = queries->findChildren(task);
0270 
0271             // THEN * 2
0272             QVERIFY(result->data().isEmpty());
0273             TestHelpers::waitForEmptyJobQueue();
0274             QVERIFY(result->data().isEmpty());
0275         }
0276     }
0277 
0278     void shouldReactToItemAddsForChildrenTask()
0279     {
0280         // GIVEN
0281         AkonadiFakeData data;
0282 
0283         // One top level collections
0284         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0285 
0286         // One task in the collection
0287         data.createItem(GenTodo().withId(42).withParent(42)
0288                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0289 
0290         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0291         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0292                                                                              serializer,
0293                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0294                                                                              Akonadi::Cache::Ptr()));
0295         auto task = serializer->createTaskFromItem(data.item(42));
0296         auto result = queries->findChildren(task);
0297         TestHelpers::waitForEmptyJobQueue();
0298         QVERIFY(result->data().isEmpty());
0299 
0300         // WHEN
0301         data.createItem(GenTodo().withId(43).withParent(42)
0302                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0303                                  .withParentUid(QStringLiteral("uid-42")));
0304         data.createItem(GenTodo().withId(44).withParent(42)
0305                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0306                                  .withParentUid(QStringLiteral("uid-42")));
0307 
0308         // THEN
0309         QCOMPARE(result->data().size(), 2);
0310         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
0311         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
0312     }
0313 
0314     void shouldReactToItemChangesForChildrenTask()
0315     {
0316         // GIVEN
0317         AkonadiFakeData data;
0318 
0319         // One top level collection
0320         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0321 
0322         // Three tasks in the collection (two being children of the first one)
0323         data.createItem(GenTodo().withId(42).withParent(42)
0324                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0325         data.createItem(GenTodo().withId(43).withParent(42)
0326                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0327                                  .withParentUid(QStringLiteral("uid-42")));
0328         data.createItem(GenTodo().withId(44).withParent(42)
0329                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0330                                  .withParentUid(QStringLiteral("uid-42")));
0331 
0332         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0333         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0334                                                                              serializer,
0335                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0336                                                                              Akonadi::Cache::Ptr()));
0337         auto task = serializer->createTaskFromItem(data.item(42));
0338         auto result = queries->findChildren(task);
0339 
0340         bool replaceHandlerCalled = false;
0341         result->addPostReplaceHandler([&replaceHandlerCalled](const Domain::Task::Ptr &, int) {
0342                                           replaceHandlerCalled = true;
0343                                       });
0344         TestHelpers::waitForEmptyJobQueue();
0345         QCOMPARE(result->data().size(), 2);
0346 
0347         // WHEN
0348         data.modifyItem(GenTodo(data.item(43)).withTitle(QStringLiteral("43bis")));
0349 
0350         // THEN
0351         QCOMPARE(result->data().size(), 2);
0352         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43bis"));
0353         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
0354 
0355         QVERIFY(replaceHandlerCalled);
0356     }
0357 
0358     void shouldRemoveItemFromCorrespondingResultWhenRelatedItemChangeForChildrenTask()
0359     {
0360         // GIVEN
0361         AkonadiFakeData data;
0362 
0363         // One top level collection
0364         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0365 
0366         // Three tasks in the collection (two being children of the first one)
0367         data.createItem(GenTodo().withId(42).withParent(42)
0368                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0369         data.createItem(GenTodo().withId(43).withParent(42)
0370                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0371                                  .withParentUid(QStringLiteral("uid-42")));
0372         data.createItem(GenTodo().withId(44).withParent(42)
0373                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0374                                  .withParentUid(QStringLiteral("uid-42")));
0375 
0376         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0377         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0378                                                                              serializer,
0379                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0380                                                                              Akonadi::Cache::Ptr()));
0381         auto task = serializer->createTaskFromItem(data.item(42));
0382         auto result = queries->findChildren(task);
0383         TestHelpers::waitForEmptyJobQueue();
0384         QCOMPARE(result->data().size(), 2);
0385 
0386         // WHEN
0387         data.modifyItem(GenTodo(data.item(43)).withParentUid(QLatin1StringView("")));
0388 
0389         // THEN
0390         QCOMPARE(result->data().size(), 1);
0391         QCOMPARE(result->data().at(0)->title(), QStringLiteral("44"));
0392     }
0393 
0394     void shouldAddItemToCorrespondingResultWhenRelatedItemChangeForChildrenTask()
0395     {
0396         // GIVEN
0397         AkonadiFakeData data;
0398 
0399         // One top level collection
0400         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0401 
0402         // Three tasks in the collection (two being top level)
0403         data.createItem(GenTodo().withId(42).withParent(42)
0404                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0405         data.createItem(GenTodo().withId(43).withParent(42)
0406                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0407         data.createItem(GenTodo().withId(44).withParent(42)
0408                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0409                                  .withParentUid(QStringLiteral("uid-42")));
0410 
0411         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0412         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0413                                                                              serializer,
0414                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0415                                                                              Akonadi::Cache::Ptr()));
0416         auto task = serializer->createTaskFromItem(data.item(42));
0417         auto result = queries->findChildren(task);
0418 
0419         bool replaceHandlerCalled = false;
0420         result->addPostReplaceHandler([&replaceHandlerCalled](const Domain::Task::Ptr &, int) {
0421                                           replaceHandlerCalled = true;
0422                                       });
0423         TestHelpers::waitForEmptyJobQueue();
0424         QCOMPARE(result->data().size(), 1);
0425 
0426         // WHEN
0427         data.modifyItem(GenTodo(data.item(43)).withParentUid(QStringLiteral("uid-42")));
0428 
0429         // THEN
0430         QCOMPARE(result->data().size(), 2);
0431         QCOMPARE(result->data().at(0)->title(), QStringLiteral("44"));
0432         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
0433 
0434         QVERIFY(!replaceHandlerCalled);
0435     }
0436 
0437     void shouldMoveItemToCorrespondingResultWhenRelatedItemChangeForChildTask()
0438     {
0439         // GIVEN
0440         AkonadiFakeData data;
0441 
0442         // One top level collection
0443         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0444 
0445         // Three tasks in the collection (two being top level)
0446         data.createItem(GenTodo().withId(42).withParent(42)
0447                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0448         data.createItem(GenTodo().withId(43).withParent(42)
0449                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0450         data.createItem(GenTodo().withId(44).withParent(42)
0451                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0452                                  .withParentUid(QStringLiteral("uid-42")));
0453 
0454         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0455         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0456                                                                              serializer,
0457                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0458                                                                              Akonadi::Cache::Ptr()));
0459         auto task1 = serializer->createTaskFromItem(data.item(42));
0460         auto task2 = serializer->createTaskFromItem(data.item(43));
0461         auto result1 = queries->findChildren(task1);
0462         auto result2 = queries->findChildren(task2);
0463 
0464         TestHelpers::waitForEmptyJobQueue();
0465         QCOMPARE(result1->data().size(), 1);
0466         QCOMPARE(result1->data().at(0)->title(), QStringLiteral("44"));
0467         QCOMPARE(result2->data().size(), 0);
0468 
0469         // WHEN
0470         data.modifyItem(GenTodo(data.item(44)).withParentUid(QStringLiteral("uid-43")));
0471 
0472         // THEN
0473         QCOMPARE(result1->data().size(), 0);
0474         QCOMPARE(result2->data().size(), 1);
0475         QCOMPARE(result2->data().at(0)->title(), QStringLiteral("44"));
0476     }
0477 
0478     void shouldReactToItemRemovesForChildrenTask()
0479     {
0480         // GIVEN
0481         AkonadiFakeData data;
0482 
0483         // One top level collection
0484         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0485 
0486         // Three tasks in the collection (two being children of the first one)
0487         data.createItem(GenTodo().withId(42).withParent(42)
0488                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0489         data.createItem(GenTodo().withId(43).withParent(42)
0490                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0491                                  .withParentUid(QStringLiteral("uid-42")));
0492         data.createItem(GenTodo().withId(44).withParent(42)
0493                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0494                                  .withParentUid(QStringLiteral("uid-42")));
0495 
0496         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0497         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0498                                                                              serializer,
0499                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0500                                                                              Akonadi::Cache::Ptr()));
0501         auto task = serializer->createTaskFromItem(data.item(42));
0502         auto result = queries->findChildren(task);
0503         TestHelpers::waitForEmptyJobQueue();
0504         QCOMPARE(result->data().size(), 2);
0505 
0506         // WHEN
0507         data.removeItem(Akonadi::Item(43));
0508 
0509         // THEN
0510         QCOMPARE(result->data().size(), 1);
0511         QCOMPARE(result->data().at(0)->title(), QStringLiteral("44"));
0512     }
0513 
0514     void shouldLookInAllReportedForTopLevelTasks()
0515     {
0516         // GIVEN
0517         AkonadiFakeData data;
0518 
0519         // Two top level collections
0520         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0521         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
0522 
0523         // One task in the first collection
0524         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0525 
0526         // Two toplevel tasks in the second collection, one with a child
0527         data.createItem(GenTodo().withId(43).withUid("parent-43").withParent(43).withTitle(QStringLiteral("43")));
0528         data.createItem(GenTodo().withId(44).withParent(43).withTitle(QStringLiteral("44")).withParentUid(QStringLiteral("2"))); // non-existing parent
0529         data.createItem(GenTodo().withId(45).withParent(43).withTitle(QStringLiteral("45")).withParentUid(QStringLiteral("parent-43"))); // existing parent
0530 
0531         // WHEN
0532         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0533                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0534                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0535                                                                              Akonadi::Cache::Ptr()));
0536         auto result = queries->findInboxTopLevel();
0537         result->data();
0538         result = queries->findInboxTopLevel(); // Should not cause any problem or wrong data
0539 
0540         // THEN
0541         QVERIFY(result->data().isEmpty());
0542         TestHelpers::waitForEmptyJobQueue();
0543 
0544         QCOMPARE(result->data().size(), 2);
0545         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0546         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
0547     }
0548 
0549     void shouldReactToItemAddsForTopLevelTasks()
0550     {
0551         // GIVEN
0552         AkonadiFakeData data;
0553 
0554         // One top level collection
0555         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0556 
0557         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0558                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0559                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0560                                                                              Akonadi::Cache::Ptr()));
0561         auto result = queries->findInboxTopLevel();
0562         TestHelpers::waitForEmptyJobQueue();
0563         QVERIFY(result->data().isEmpty());
0564 
0565         // WHEN
0566         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
0567         data.createItem(GenTodo().withId(43).withParent(42).withTitle(QStringLiteral("43")).withParentUid(QStringLiteral("2")));
0568 
0569         // THEN
0570         QCOMPARE(result->data().size(), 1);
0571         QCOMPARE(result->data().first()->title(), QStringLiteral("42"));
0572     }
0573 
0574     void shouldReactToItemRemovesForTopLevelTasks()
0575     {
0576         // GIVEN
0577         AkonadiFakeData data;
0578 
0579         // One top level collection
0580         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0581 
0582         // Three tasks in the collection (one being child of the second one)
0583         data.createItem(GenTodo().withId(42).withParent(42)
0584                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0585         data.createItem(GenTodo().withId(43).withParent(42)
0586                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0587         data.createItem(GenTodo().withId(44).withParent(42)
0588                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0589                                  .withParentUid(QStringLiteral("uid-43")));
0590 
0591         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0592                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0593                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0594                                                                              Akonadi::Cache::Ptr()));
0595         auto result = queries->findInboxTopLevel();
0596         TestHelpers::waitForEmptyJobQueue();
0597         QCOMPARE(result->data().size(), 2);
0598 
0599         // WHEN
0600         data.removeItem(Akonadi::Item(43));
0601 
0602         // THEN
0603         QCOMPARE(result->data().size(), 1);
0604         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0605     }
0606 
0607     void shouldReactToItemChangesForTopLevelTasks()
0608     {
0609         // GIVEN
0610         AkonadiFakeData data;
0611 
0612         // One top level collection
0613         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0614 
0615         // Three tasks in the collection (one being child of the second one)
0616         data.createItem(GenTodo().withId(42).withParent(42)
0617                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0618         data.createItem(GenTodo().withId(43).withParent(42)
0619                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0620         data.createItem(GenTodo().withId(44).withParent(42)
0621                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0622                                  .withParentUid(QStringLiteral("uid-43")));
0623 
0624         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0625                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0626                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0627                                                                              Akonadi::Cache::Ptr()));
0628         auto result = queries->findInboxTopLevel();
0629         // Even though the pointer didn't change it's convenient to user if we call
0630         // the replace handlers
0631         bool replaceHandlerCalled = false;
0632         result->addPostReplaceHandler([&replaceHandlerCalled](const Domain::Task::Ptr &, int) {
0633                                           replaceHandlerCalled = true;
0634                                       });
0635         TestHelpers::waitForEmptyJobQueue();
0636         QCOMPARE(result->data().size(), 2);
0637 
0638         // WHEN
0639         data.modifyItem(GenTodo(data.item(43)).withTitle(QStringLiteral("43bis")));
0640 
0641         // THEN
0642         QCOMPARE(result->data().size(), 2);
0643         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0644         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43bis"));
0645         QVERIFY(replaceHandlerCalled);
0646     }
0647 
0648     void shouldRemoveItemFromTopLevelResultWhenRelatedItemChangeForTopLevelTask()
0649     {
0650         // GIVEN
0651         AkonadiFakeData data;
0652 
0653         // One top level collection
0654         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0655 
0656         // Three tasks in the collection (one being child of the second one)
0657         data.createItem(GenTodo().withId(42).withParent(42)
0658                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0659         data.createItem(GenTodo().withId(43).withParent(42)
0660                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0661         data.createItem(GenTodo().withId(44).withParent(42)
0662                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0663                                  .withParentUid(QStringLiteral("uid-43")));
0664 
0665         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0666                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0667                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0668                                                                              Akonadi::Cache::Ptr()));
0669         auto result = queries->findInboxTopLevel();
0670         TestHelpers::waitForEmptyJobQueue();
0671         QCOMPARE(result->data().size(), 2);
0672 
0673         // WHEN
0674         data.modifyItem(GenTodo(data.item(43)).withParentUid(QStringLiteral("uid-42")));
0675 
0676         // THEN
0677         QCOMPARE(result->data().size(), 1);
0678         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0679     }
0680 
0681     void shouldAddItemToTopLevelResultWhenRelatedItemChangeForChildrenTask()
0682     {
0683         // GIVEN
0684         AkonadiFakeData data;
0685 
0686         // One top level collection
0687         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0688 
0689         // Three tasks in the collection (one being child of the second one)
0690         data.createItem(GenTodo().withId(42).withParent(42)
0691                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0692         data.createItem(GenTodo().withId(43).withParent(42)
0693                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
0694                                  .withParentUid(QStringLiteral("uid-42")));
0695         data.createItem(GenTodo().withId(44).withParent(42)
0696                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0697                                  .withParentUid(QStringLiteral("uid-43")));
0698 
0699         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0700                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0701                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0702                                                                              Akonadi::Cache::Ptr()));
0703         auto result = queries->findInboxTopLevel();
0704         TestHelpers::waitForEmptyJobQueue();
0705         QCOMPARE(result->data().size(), 1);
0706 
0707         // WHEN
0708         data.modifyItem(GenTodo(data.item(43)).withParentUid(QString()));
0709 
0710         // THEN
0711         QCOMPARE(result->data().size(), 2);
0712         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
0713         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
0714     }
0715 
0716     void shouldRemoveParentNodeAndMoveChildrenInTopLevelResult()
0717     {
0718         // GIVEN
0719         AkonadiFakeData data;
0720 
0721         // One top level collection
0722         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0723 
0724         // Three tasks in the collection (one being child of the second one)
0725         data.createItem(GenTodo().withId(42).withParent(42)
0726                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0727         data.createItem(GenTodo().withId(43).withParent(42)
0728                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0729         data.createItem(GenTodo().withId(44).withParent(42)
0730                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0731                                  .withParentUid(QStringLiteral("uid-43")));
0732 
0733         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0734                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
0735                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0736                                                                              Akonadi::Cache::Ptr()));
0737         auto result = queries->findInboxTopLevel();
0738         TestHelpers::waitForEmptyJobQueue();
0739         QCOMPARE(result->data().size(), 2);
0740 
0741         auto resultChild = queries->findChildren(result->data().at(1));
0742         TestHelpers::waitForEmptyJobQueue();
0743         QCOMPARE(resultChild->data().size(), 1);
0744 
0745         // WHEN
0746         data.removeItem(Akonadi::Item(43));
0747 
0748         // THEN
0749         QCOMPARE(resultChild->data().size(), 0);
0750         QCOMPARE(result->data().size(), 1); // FIXME: Should become 2 once we got a proper cache in place
0751     }
0752 
0753     void shouldNotCrashDuringFindChildrenWhenJobIsKilled()
0754     {
0755         // GIVEN
0756         AkonadiFakeData data;
0757 
0758         // One top level collection
0759         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0760 
0761         // Three tasks in the collection (two being children of the first one)
0762         data.createItem(GenTodo().withId(42).withParent(42)
0763                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0764         data.createItem(GenTodo().withId(43).withParent(42)
0765                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0766         data.createItem(GenTodo().withId(44).withParent(42)
0767                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0768                                  .withParentUid(QStringLiteral("uid-42")));
0769 
0770         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0771         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
0772                                                                              serializer,
0773                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
0774                                                                              Akonadi::Cache::Ptr()));
0775 
0776         data.storageBehavior().setFetchItemErrorCode(42, KJob::KilledJobError);
0777 
0778         // WHEN
0779         auto task1 = serializer->createTaskFromItem(data.item(42));
0780         auto result = queries->findChildren(task1);
0781 
0782         // THEN
0783         QVERIFY(result->data().isEmpty());
0784         TestHelpers::waitForEmptyJobQueue();
0785         QVERIFY(result->data().isEmpty());
0786     }
0787 
0788 
0789     void shouldNotCrashDuringFindChildrenWhenItemsJobReceiveResult_data()
0790     {
0791         QTest::addColumn<int>("errorCode");
0792         QTest::addColumn<int>("fetchBehavior");
0793         QTest::addColumn<bool>("deleteQuery");
0794 
0795         QTest::newRow("No error with empty list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::EmptyFetch) << false;
0796         QTest::newRow("Error with empty list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::EmptyFetch) << true;
0797         QTest::newRow("Error with list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::NormalFetch) << true;
0798     }
0799 
0800     void shouldNotCrashDuringFindChildrenWhenItemsJobReceiveResult()
0801     {
0802         // GIVEN
0803         AkonadiFakeData data;
0804 
0805         // One top level collection
0806         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0807 
0808         // Three tasks in the collection (two being children of the first one)
0809         data.createItem(GenTodo().withId(42).withParent(42)
0810                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0811         data.createItem(GenTodo().withId(43).withParent(42)
0812                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0813         data.createItem(GenTodo().withId(44).withParent(42)
0814                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0815                                  .withParentUid(QStringLiteral("uid-42")));
0816 
0817         auto storage = Akonadi::StorageInterface::Ptr(data.createStorage());
0818         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0819         auto monitor = Akonadi::MonitorInterface::Ptr(data.createMonitor());
0820         std::unique_ptr<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
0821                                                                              serializer,
0822                                                                              monitor,
0823                                                                              Akonadi::Cache::Ptr()));
0824 
0825         QFETCH(int, errorCode);
0826         QFETCH(int, fetchBehavior);
0827         QFETCH(bool, deleteQuery);
0828 
0829         data.storageBehavior().setFetchItemsErrorCode(42, errorCode);
0830         data.storageBehavior().setFetchItemsBehavior(42, AkonadiFakeStorageBehavior::FetchBehavior(fetchBehavior));
0831 
0832         // WHEN
0833         auto task1 = serializer->createTaskFromItem(data.item(42));
0834         auto result = queries->findChildren(task1);
0835 
0836         if (deleteQuery)
0837             delete queries.release();
0838 
0839         // THEN
0840         QVERIFY(result->data().isEmpty());
0841         TestHelpers::waitForEmptyJobQueue();
0842         QVERIFY(result->data().isEmpty());
0843     }
0844 
0845     void shouldNotCrashDuringFindAllWhenFetchJobFailedOrEmpty_data()
0846     {
0847         QTest::addColumn<int>("colErrorCode");
0848         QTest::addColumn<int>("colFetchBehavior");
0849         QTest::addColumn<int>("itemsErrorCode");
0850         QTest::addColumn<int>("itemsFetchBehavior");
0851         QTest::addColumn<bool>("deleteQuery");
0852 
0853         QTest::newRow("No error with empty collection list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0854                                                              << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0855                                                              << false;
0856 
0857         QTest::newRow("Error with empty collection list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0858                                                           << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0859                                                           << true;
0860 
0861         QTest::newRow("Error with collection list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0862                                                     << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0863                                                     << true;
0864 
0865         QTest::newRow("No error with empty item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0866                                                        << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0867                                                        << false;
0868 
0869         QTest::newRow("Error with empty item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0870                                                     << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0871                                                     << false;
0872 
0873         QTest::newRow("Error with item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0874                                               << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0875                                               << false;
0876     }
0877 
0878     void shouldNotCrashDuringFindAllWhenFetchJobFailedOrEmpty()
0879     {
0880         // GIVEN
0881         AkonadiFakeData data;
0882 
0883         // One top level collection
0884         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0885 
0886         // Three tasks in the collection
0887         data.createItem(GenTodo().withId(42).withParent(42)
0888                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0889         data.createItem(GenTodo().withId(43).withParent(42)
0890                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0891         data.createItem(GenTodo().withId(44).withParent(42)
0892                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")));
0893 
0894         auto storage = Akonadi::StorageInterface::Ptr(data.createStorage());
0895         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0896         auto monitor = Akonadi::MonitorInterface::Ptr(data.createMonitor());
0897         std::unique_ptr<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
0898                                                                              serializer,
0899                                                                              monitor,
0900                                                                              Akonadi::Cache::Ptr()));
0901 
0902         QFETCH(int, colErrorCode);
0903         QFETCH(int, colFetchBehavior);
0904         data.storageBehavior().setFetchCollectionsErrorCode(Akonadi::Collection::root().id(), colErrorCode);
0905         data.storageBehavior().setFetchCollectionsBehavior(Akonadi::Collection::root().id(),
0906                                                            AkonadiFakeStorageBehavior::FetchBehavior(colFetchBehavior));
0907 
0908         QFETCH(int, itemsErrorCode);
0909         QFETCH(int, itemsFetchBehavior);
0910         data.storageBehavior().setFetchItemsErrorCode(42, itemsErrorCode);
0911         data.storageBehavior().setFetchItemsBehavior(42, AkonadiFakeStorageBehavior::FetchBehavior(itemsFetchBehavior));
0912 
0913         QFETCH(bool, deleteQuery);
0914 
0915 
0916         // WHEN
0917         auto result = queries->findAll();
0918 
0919         if (deleteQuery)
0920             delete queries.release();
0921 
0922         // THEN
0923         QVERIFY(result->data().isEmpty());
0924         TestHelpers::waitForEmptyJobQueue();
0925         QVERIFY(result->data().isEmpty());
0926     }
0927 
0928     void shouldNotCrashDuringFindTopLevelWhenFetchJobFailedOrEmpty_data()
0929     {
0930         QTest::addColumn<int>("colErrorCode");
0931         QTest::addColumn<int>("colFetchBehavior");
0932         QTest::addColumn<int>("itemsErrorCode");
0933         QTest::addColumn<int>("itemsFetchBehavior");
0934         QTest::addColumn<bool>("deleteQuery");
0935 
0936         QTest::newRow("No error with empty collection list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0937                                                              << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0938                                                              << false;
0939 
0940         QTest::newRow("Error with empty collection list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0941                                                           << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0942                                                           << true;
0943 
0944         QTest::newRow("Error with collection list") << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0945                                                     << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0946                                                     << true;
0947 
0948         QTest::newRow("No error with empty item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0949                                                        << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0950                                                        << false;
0951 
0952         QTest::newRow("Error with empty item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0953                                                     << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::EmptyFetch)
0954                                                     << false;
0955 
0956         QTest::newRow("Error with item list") << int(KJob::NoError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0957                                               << int(KJob::KilledJobError) << int(AkonadiFakeStorageBehavior::NormalFetch)
0958                                               << false;
0959     }
0960 
0961     void shouldNotCrashDuringFindTopLevelWhenFetchJobFailedOrEmpty()
0962     {
0963         // GIVEN
0964         AkonadiFakeData data;
0965 
0966         // One top level collection
0967         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
0968 
0969         // Three tasks in the collection (third one being child of the first one)
0970         data.createItem(GenTodo().withId(42).withParent(42)
0971                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
0972         data.createItem(GenTodo().withId(43).withParent(42)
0973                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
0974         data.createItem(GenTodo().withId(44).withParent(42)
0975                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
0976                                  .withParentUid(QStringLiteral("uid-42")));
0977 
0978         auto storage = Akonadi::StorageInterface::Ptr(data.createStorage());
0979         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
0980         auto monitor = Akonadi::MonitorInterface::Ptr(data.createMonitor());
0981         std::unique_ptr<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
0982                                                                              serializer,
0983                                                                              monitor,
0984                                                                              Akonadi::Cache::Ptr()));
0985 
0986         QFETCH(int, colErrorCode);
0987         QFETCH(int, colFetchBehavior);
0988         data.storageBehavior().setFetchCollectionsErrorCode(Akonadi::Collection::root().id(), colErrorCode);
0989         data.storageBehavior().setFetchCollectionsBehavior(Akonadi::Collection::root().id(),
0990                                                            AkonadiFakeStorageBehavior::FetchBehavior(colFetchBehavior));
0991 
0992         QFETCH(int, itemsErrorCode);
0993         QFETCH(int, itemsFetchBehavior);
0994         data.storageBehavior().setFetchItemsErrorCode(42, itemsErrorCode);
0995         data.storageBehavior().setFetchItemsBehavior(42, AkonadiFakeStorageBehavior::FetchBehavior(itemsFetchBehavior));
0996 
0997         QFETCH(bool, deleteQuery);
0998 
0999 
1000         // WHEN
1001         auto result = queries->findInboxTopLevel();
1002 
1003         if (deleteQuery)
1004             delete queries.release();
1005 
1006         // THEN
1007         QVERIFY(result->data().isEmpty());
1008         TestHelpers::waitForEmptyJobQueue();
1009         QVERIFY(result->data().isEmpty());
1010     }
1011 
1012     void shouldIgnoreProjectsWhenReportingTopLevelTasks()
1013     {
1014         // GIVEN
1015         AkonadiFakeData data;
1016 
1017         // Two top level collections
1018         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1019         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1020 
1021         // One task in the first collection
1022         data.createItem(GenTodo().withId(42).withParent(42)
1023                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
1024 
1025         // Two tasks and one project in the second collection
1026         data.createItem(GenTodo().withId(43).withParent(43)
1027                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
1028         data.createItem(GenTodo().withId(44).withParent(43)
1029                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
1030                                  .withParentUid(QStringLiteral("uid-43")));
1031         data.createItem(GenTodo().withId(45).withParent(43)
1032                                  .withTitle(QStringLiteral("45")).withUid(QStringLiteral("uid-45"))
1033                                  .asProject());
1034 
1035         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1036                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1037                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1038                                                                              Akonadi::Cache::Ptr()));
1039         auto result = queries->findInboxTopLevel();
1040         result->data();
1041         result = queries->findInboxTopLevel(); // Should not cause any problem or wrong data
1042 
1043         // THEN
1044         QVERIFY(result->data().isEmpty());
1045         TestHelpers::waitForEmptyJobQueue();
1046 
1047         QCOMPARE(result->data().size(), 2);
1048         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1049         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
1050     }
1051 
1052     void shouldLookInAllSelectedCollectionsForInboxTopLevel()
1053     {
1054         // GIVEN
1055         AkonadiFakeData data;
1056 
1057         // Three top level collections
1058         data.createCollection(GenCollection().withId(42).withRootAsParent().withNoteContent());
1059         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1060         data.createCollection(GenCollection().withId(44).withRootAsParent().withTaskContent().selected(false));
1061 
1062         // Two tasks in the second collection
1063         data.createItem(GenTodo().withId(43).withParent(43).withTitle(QStringLiteral("43")));
1064         data.createItem(GenTodo().withId(44).withParent(43).withTitle(QStringLiteral("44")));
1065 
1066         // One task in the third collection
1067         data.createItem(GenTodo().withId(45).withParent(44).withTitle(QStringLiteral("45")));
1068 
1069         // WHEN
1070         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1071                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1072                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1073                                                                              Akonadi::Cache::Ptr()));
1074         auto result = queries->findInboxTopLevel();
1075         result->data();
1076         result = queries->findInboxTopLevel(); // Should not cause any problem or wrong data
1077 
1078         // THEN
1079         QVERIFY(result->data().isEmpty());
1080         TestHelpers::waitForEmptyJobQueue();
1081 
1082         QCOMPARE(result->data().size(), 2);
1083         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
1084         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
1085     }
1086 
1087     void shouldIgnoreItemsWhichAreNotTasksInInboxTopLevel()
1088     {
1089         // GIVEN
1090         AkonadiFakeData data;
1091 
1092         // One top level collection
1093         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1094 
1095         // Two items in the collection
1096         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
1097         // One of them is not a task
1098         auto item = Akonadi::Item(43);
1099         item.setPayloadFromData("FooBar");
1100         item.setParentCollection(Akonadi::Collection(42));
1101         data.createItem(item);
1102 
1103         // WHEN
1104         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1105                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1106                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1107                                                                              Akonadi::Cache::Ptr()));
1108         auto result = queries->findInboxTopLevel();
1109 
1110         // THEN
1111         QVERIFY(result->data().isEmpty());
1112         TestHelpers::waitForEmptyJobQueue();
1113 
1114         QCOMPARE(result->data().size(), 1);
1115         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1116     }
1117 
1118     void shouldNotHaveTasksWithParentsInInboxTopLevel()
1119     {
1120         // TODO: Note that this specification is kind of an over simplification which
1121         // assumes that all the underlying data is correct. Ideally it should be checked
1122         // that the uid referred to actually points to a todo which exists in a proper
1123         // collection. We will need a cache to be able to implement that properly though.
1124 
1125         // GIVEN
1126         AkonadiFakeData data;
1127 
1128         // One top level collection
1129         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1130 
1131         // Three items in the collection
1132         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
1133         data.createItem(GenTodo().withId(43).withParent(42).withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")).withParentUid(QStringLiteral("uid-42")));
1134         data.createItem(GenTodo().withId(44).withParent(42).withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")).withParentUid(QStringLiteral("foo")));
1135 
1136         // WHEN
1137         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1138                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1139                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1140                                                                              Akonadi::Cache::Ptr()));
1141         auto result = queries->findInboxTopLevel();
1142 
1143         // THEN
1144         QVERIFY(result->data().isEmpty());
1145         TestHelpers::waitForEmptyJobQueue();
1146 
1147         QCOMPARE(result->data().size(), 1);
1148         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1149     }
1150 
1151     void shouldHaveTasksWithContextsInInboxTopLevel_data()
1152     {
1153         QTest::addColumn<bool>("hasContexts");
1154         QTest::addColumn<bool>("isExpectedInInbox");
1155 
1156         QTest::newRow("task with no context") << false << true;
1157         QTest::newRow("task with contexts") << true << true;
1158     }
1159 
1160     void shouldHaveTasksWithContextsInInboxTopLevel()
1161     {
1162         // GIVEN
1163         AkonadiFakeData data;
1164 
1165         // One top level collection
1166         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1167 
1168         // One context item
1169         data.createItem(GenTodo().withParent(42).withId(1).withUid("ctx-42").withTitle(QStringLiteral("Context 42")).asContext());
1170 
1171         // One item in the collection
1172         QFETCH(bool, hasContexts);
1173         auto contextUids = QStringList();
1174         if (hasContexts) contextUids << "ctx-42";
1175 
1176         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")).withContexts(contextUids));
1177 
1178         // WHEN
1179         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1180                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1181                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1182                                                                              Akonadi::Cache::Ptr()));
1183         auto result = queries->findInboxTopLevel();
1184 
1185         // THEN
1186         QVERIFY(result->data().isEmpty());
1187         TestHelpers::waitForEmptyJobQueue();
1188 
1189         QFETCH(bool, isExpectedInInbox);
1190         if (isExpectedInInbox) {
1191             QCOMPARE(result->data().size(), 1);
1192             QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1193         } else {
1194             QVERIFY(result->data().isEmpty());
1195         }
1196     }
1197 
1198     void shouldReactToItemAddsForInboxTopLevel_data()
1199     {
1200         QTest::addColumn<bool>("reactionExpected");
1201         QTest::addColumn<QString>("relatedUid");
1202         QTest::addColumn<bool>("hasContexts");
1203 
1204         QTest::newRow("task which should be in inbox") << true << QString() << false;
1205         QTest::newRow("task with related uid") << false << "foo" << false;
1206         QTest::newRow("task with context") << true << QString() << true;
1207     }
1208 
1209     void shouldReactToItemAddsForInboxTopLevel()
1210     {
1211         // GIVEN
1212         AkonadiFakeData data;
1213 
1214         // One top level collection
1215         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1216 
1217         // One context item
1218         data.createItem(GenTodo().withParent(42).withId(1).withUid("ctx-42").withTitle(QStringLiteral("Context 1")).asContext());
1219 
1220         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1221                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1222                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1223                                                                              Akonadi::Cache::Ptr()));
1224         auto result = queries->findInboxTopLevel();
1225         TestHelpers::waitForEmptyJobQueue();
1226         QVERIFY(result->data().isEmpty());
1227 
1228         // WHEN
1229         QFETCH(QString, relatedUid);
1230         QFETCH(bool, hasContexts);
1231         auto contextUids = QStringList();
1232         if (hasContexts) contextUids << "ctx-42";
1233 
1234         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")).withContexts(contextUids).withParentUid(relatedUid));
1235 
1236         // THEN
1237         QFETCH(bool, reactionExpected);
1238         if (reactionExpected) {
1239             QCOMPARE(result->data().size(), 1);
1240             QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1241         } else {
1242             QVERIFY(result->data().isEmpty());
1243         }
1244     }
1245 
1246     void shouldReactToItemRemovesForInboxTopLevel()
1247     {
1248         // GIVEN
1249         AkonadiFakeData data;
1250 
1251         // One top level collection
1252         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1253 
1254         // One item in the collection
1255         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
1256 
1257         // WHEN
1258         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1259                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1260                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1261                                                                              Akonadi::Cache::Ptr()));
1262         auto result = queries->findInboxTopLevel();
1263         TestHelpers::waitForEmptyJobQueue();
1264         QCOMPARE(result->data().size(), 1);
1265         QCOMPARE(result->data().first()->title(), QStringLiteral("42"));
1266 
1267         // WHEN
1268         data.removeItem(Akonadi::Item(42));
1269 
1270         // THEN
1271         QVERIFY(result->data().isEmpty());
1272     }
1273 
1274     void shouldReactToItemChangesForInboxTopLevel_data()
1275     {
1276         QTest::addColumn<bool>("inListAfterChange");
1277         QTest::addColumn<QString>("relatedUidBefore");
1278         QTest::addColumn<QString>("relatedUidAfter");
1279 
1280         QTest::newRow("task appears in inbox (related uid)") << true << "foo" << QString();
1281         QTest::newRow("task disappears from inbox (related uid)") << false << QString() << "foo";
1282     }
1283 
1284     void shouldReactToItemChangesForInboxTopLevel()
1285     {
1286         // GIVEN
1287         AkonadiFakeData data;
1288 
1289         // One top level collection
1290         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1291 
1292         // One context item
1293         data.createItem(GenTodo().withParent(42).withId(1).withUid("ctx-42").withTitle(QStringLiteral("Context 1")).asContext());
1294 
1295         // Task data
1296         QFETCH(QString, relatedUidBefore);
1297 
1298         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")).withParentUid(relatedUidBefore));
1299 
1300         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1301                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1302                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1303                                                                              Akonadi::Cache::Ptr()));
1304         auto result = queries->findInboxTopLevel();
1305         TestHelpers::waitForEmptyJobQueue();
1306 
1307         QFETCH(bool, inListAfterChange);
1308 
1309         if (inListAfterChange) {
1310             QVERIFY(result->data().isEmpty());
1311         } else {
1312             QCOMPARE(result->data().size(), 1);
1313             QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1314         }
1315 
1316         // WHEN
1317         QFETCH(QString, relatedUidAfter);
1318 
1319         data.modifyItem(GenTodo(data.item(42)).withParentUid(relatedUidAfter));
1320 
1321         // THEN
1322         if (inListAfterChange) {
1323             QCOMPARE(result->data().size(), 1);
1324             QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1325         } else {
1326             QVERIFY(result->data().isEmpty());
1327         }
1328     }
1329 
1330     void shouldReactToCollectionSelectionChangesForInboxTopLevel()
1331     {
1332         // GIVEN
1333         AkonadiFakeData data;
1334 
1335         // Two top level collections
1336         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1337         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1338 
1339         // One task in each collection
1340         data.createItem(GenTodo().withId(42).withParent(42).withTitle(QStringLiteral("42")));
1341         data.createItem(GenTodo().withId(43).withParent(43).withTitle(QStringLiteral("43")));
1342 
1343         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(Akonadi::StorageInterface::Ptr(data.createStorage()),
1344                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1345                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1346                                                                              Akonadi::Cache::Ptr()));
1347         auto result = queries->findInboxTopLevel();
1348         TestHelpers::waitForEmptyJobQueue();
1349         QCOMPARE(result->data().size(), 2);
1350         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1351         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
1352 
1353         // WHEN
1354         data.modifyCollection(GenCollection(data.collection(43)).selected(false));
1355         TestHelpers::waitForEmptyJobQueue();
1356 
1357         // THEN
1358         QCOMPARE(result->data().size(), 1);
1359         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1360     }
1361 
1362     void shouldLookInAllWorkdayReportedForAllTasks_data()
1363     {
1364         QTest::addColumn<bool>("isExpectedInWorkday");
1365         QTest::addColumn<Akonadi::Item>("item2");
1366 
1367         const auto today = Utils::DateTime::currentDate();
1368 
1369         QTest::newRow("todayTask") << true
1370                                    << Akonadi::Item(GenTodo()
1371                                                     .withStartDate(today)
1372                                                     .withDueDate(today));
1373 
1374         QTest::newRow("pastTask") << true
1375                                   << Akonadi::Item(GenTodo()
1376                                                    .withStartDate(today.addDays(-42))
1377                                                    .withDueDate(today.addDays(-41)));
1378 
1379         QTest::newRow("startTodayTask") << true
1380                                         << Akonadi::Item(GenTodo()
1381                                                          .withStartDate(today));
1382 
1383         QTest::newRow("endTodayTask") << true
1384                                       << Akonadi::Item(GenTodo()
1385                                                        .withStartDate(today));
1386 
1387         QTest::newRow("futureTask") << false
1388                                     << Akonadi::Item(GenTodo()
1389                                                      .withStartDate(today.addDays(41))
1390                                                      .withDueDate(today.addDays(42)));
1391 
1392         QTest::newRow("pastDoneTask") << false
1393                                       << Akonadi::Item(GenTodo()
1394                                                        .withStartDate(today.addDays(-42))
1395                                                        .withDueDate(today.addDays(-41))
1396                                                        .done()
1397                                                        .withDoneDate(today.addDays(-30)));
1398 
1399         QTest::newRow("todayDoneTask") << true
1400                                        << Akonadi::Item(GenTodo()
1401                                                         .withStartDate(today)
1402                                                         .withDueDate(today)
1403                                                         .done()
1404                                                         .withDoneDate(today));
1405 
1406         QTest::newRow("startTodayDoneTask") << true
1407                                             << Akonadi::Item(GenTodo()
1408                                                              .withStartDate(today)
1409                                                              .done()
1410                                                              .withDoneDate(today));
1411 
1412         QTest::newRow("endTodayDoneTask") << true
1413                                           << Akonadi::Item(GenTodo()
1414                                                            .withDueDate(today)
1415                                                            .done()
1416                                                            .withDoneDate(today));
1417     }
1418 
1419     void shouldLookInAllWorkdayReportedForAllTasks()
1420     {
1421         // GIVEN
1422         const auto today = Utils::DateTime::currentDate();
1423         AkonadiFakeData data;
1424 
1425         // Two top level collections
1426         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1427         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1428 
1429         // One task in the first collection
1430         data.createItem(GenTodo().withId(42).withParent(42)
1431                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1432                                  .withStartDate(today));
1433 
1434         // One task in the second collection (from data driven set)
1435         QFETCH(Akonadi::Item, item2);
1436         data.createItem(GenTodo(item2).withId(43).withParent(43)
1437                                       .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
1438 
1439         // WHEN
1440         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1441         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1442         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(createCachingStorage(data, cache),
1443                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1444                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1445                                                                              cache));
1446         auto result = queries->findWorkdayTopLevel();
1447         result->data();
1448         result = queries->findWorkdayTopLevel(); // Should not cause any problem or wrong data
1449 
1450         // THEN
1451         QVERIFY(result->data().isEmpty());
1452         TestHelpers::waitForEmptyJobQueue();
1453 
1454         QFETCH(bool, isExpectedInWorkday);
1455 
1456         const int sizeExpected = (isExpectedInWorkday) ? 2 : 1;
1457 
1458         QCOMPARE(result->data().size(), sizeExpected);
1459         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1460 
1461         if (isExpectedInWorkday)
1462             QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
1463     }
1464 
1465     void shouldLookInAllWorkdayReportedForAllTasksWhenOverrideDate()
1466     {
1467         // GIVEN
1468         qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-10");
1469         const auto today = Utils::DateTime::currentDate();
1470         AkonadiFakeData data;
1471 
1472         // Two top level collections
1473         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1474         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1475 
1476         // One task in the first collection
1477         data.createItem(GenTodo().withId(42).withParent(42)
1478                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1479                                  .withStartDate(today));
1480 
1481         // One task in the second collection
1482         data.createItem(GenTodo().withId(43).withParent(43)
1483                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
1484                                  .withStartDate(today));
1485 
1486         // WHEN
1487         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1488         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1489         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(createCachingStorage(data, cache),
1490                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1491                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1492                                                                              cache));
1493         auto result = queries->findWorkdayTopLevel();
1494         result->data();
1495         result = queries->findWorkdayTopLevel(); // Should not cause any problem or wrong data
1496 
1497         // THEN
1498         QVERIFY(result->data().isEmpty());
1499         TestHelpers::waitForEmptyJobQueue();
1500 
1501         QCOMPARE(result->data().size(), 2);
1502         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1503         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
1504     }
1505 
1506     void shouldPollForCurrentDayToListWorkday()
1507     {
1508         // GIVEN
1509         qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-10");
1510         const auto today = Utils::DateTime::currentDate();
1511         AkonadiFakeData data;
1512 
1513         // Two top level collections
1514         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1515         data.createCollection(GenCollection().withId(43).withRootAsParent().withTaskContent());
1516 
1517         // One task in the first collection
1518         data.createItem(GenTodo().withId(42).withParent(42)
1519                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1520                                  .withStartDate(today));
1521 
1522         // One task in the second collection
1523         data.createItem(GenTodo().withId(43).withParent(43)
1524                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
1525                                  .withStartDate(today.addDays(1)));
1526 
1527         QScopedPointer<Domain::TaskQueries> queries;
1528         {
1529             auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1530             auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1531             auto akqueries = new Akonadi::TaskQueries(createCachingStorage(data, cache),
1532                                                       Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1533                                                       Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1534                                                       cache);
1535             QCOMPARE(akqueries->workdayPollInterval(), 30000);
1536             akqueries->setWorkdayPollInterval(500);
1537             queries.reset(akqueries);
1538         }
1539         auto result = queries->findWorkdayTopLevel();
1540         TestHelpers::waitForEmptyJobQueue();
1541         QCOMPARE(result->data().size(), 1);
1542         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1543 
1544         // WHEN
1545         qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-11");
1546         QTest::qWait(1000);
1547         TestHelpers::waitForEmptyJobQueue();
1548 
1549         // THEN
1550         QCOMPARE(result->data().size(), 2);
1551         QCOMPARE(result->data().at(0)->title(), QStringLiteral("42"));
1552         QCOMPARE(result->data().at(1)->title(), QStringLiteral("43"));
1553     }
1554 
1555     void shouldNotListWorkdayTasksTwiceIfTheyHaveAParentInWorkday()
1556     {
1557         // GIVEN
1558         const auto today = Utils::DateTime::currentDate();
1559         AkonadiFakeData data;
1560 
1561         // One top level collection
1562         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1563 
1564         // One context item
1565         data.createItem(GenTodo().withParent(42).withId(1).withUid("ctx-42").withTitle(QStringLiteral("Context 1")).asContext());
1566 
1567         // Five tasks in the collection, two start today, three not, all forming an ancestry line
1568         data.createItem(GenTodo().withParent(42).withId(42).withTitle(QStringLiteral("42")).withUid("42"));
1569         data.createItem(GenTodo().withParent(42).withId(43).withTitle(QStringLiteral("43")).withUid("43").withParentUid("42").withStartDate(today));
1570         data.createItem(GenTodo().withParent(42).withId(44).withTitle(QStringLiteral("44")).withUid("44").withParentUid("43"));
1571         data.createItem(GenTodo().withParent(42).withId(45).withTitle(QStringLiteral("45")).withUid("45").withParentUid("44").withStartDate(today));
1572         data.createItem(GenTodo().withParent(42).withId(46).withTitle(QStringLiteral("46")).withUid("46").withParentUid("45"));
1573 
1574         // WHEN
1575         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1576         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1577         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(createCachingStorage(data, cache),
1578                                                                              Akonadi::Serializer::Ptr(new Akonadi::Serializer),
1579                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1580                                                                              cache));
1581         auto result = queries->findWorkdayTopLevel();
1582         result->data();
1583         result = queries->findWorkdayTopLevel(); // Should not cause any problem or wrong data
1584 
1585         // THEN
1586         QVERIFY(result->data().isEmpty());
1587         TestHelpers::waitForEmptyJobQueue();
1588 
1589         QCOMPARE(result->data().size(), 1);
1590         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
1591 
1592         // Should not change anything
1593         result = queries->findWorkdayTopLevel();
1594         TestHelpers::waitForEmptyJobQueue();
1595 
1596         QCOMPARE(result->data().size(), 1);
1597         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
1598     }
1599 
1600     void findProjectShouldLookInCollection()
1601     {
1602         // GIVEN
1603         AkonadiFakeData data;
1604 
1605         // One top level collection
1606         auto collection = GenCollection().withId(42).withRootAsParent().withTaskContent();
1607         data.createCollection(collection);
1608 
1609         // Three tasks in the collection (two being children of the first one)
1610         data.createItem(GenTodo().withId(42).asProject().withParent(42)
1611                                  .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42")));
1612         data.createItem(GenTodo().withId(43).withParent(42)
1613                                  .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43"))
1614                                  .withParentUid(QStringLiteral("uid-42")));
1615         data.createItem(GenTodo().withId(44).withParent(42)
1616                                  .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44"))
1617                                  .withParentUid(QStringLiteral("uid-42")));
1618 
1619         // WHEN
1620         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1621 
1622         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1623         auto storage = createCachingStorage(data, cache);
1624         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1625                                                                              serializer,
1626                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1627                                                                              cache));
1628         auto task = serializer->createTaskFromItem(data.item(44));
1629         // populate cache for collection
1630         auto *fetchJob = storage->fetchItems(collection, nullptr);
1631         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1632 
1633         auto result = queries->findProject(task);
1634 
1635         // THEN
1636         QVERIFY(result);
1637         TestHelpers::waitForEmptyJobQueue();
1638         QCOMPARE(result->data().size(), 1);
1639         QCOMPARE(result->data().at(0)->name(), QStringLiteral("42"));
1640 
1641         // Should not change anything
1642         result = queries->findProject(task);
1643 
1644         QCOMPARE(result->data().size(), 1);
1645         QCOMPARE(result->data().at(0)->name(), QStringLiteral("42"));
1646     }
1647 
1648     void findProjectShouldReactToRelationshipChange()
1649     {
1650         // GIVEN
1651         AkonadiFakeData data;
1652 
1653         // One top level collection
1654         const Akonadi::Collection::Id colId = 42;
1655         auto collection = GenCollection().withId(colId).withRootAsParent().withTaskContent();
1656         data.createCollection(collection);
1657 
1658         // Three tasks in the collection (two being children of the first one)
1659         // 1->2->3 (project) where 1 changes to 1->4->5 (project)
1660         data.createItem(GenTodo().withId(3).asProject().withParent(colId)
1661                                  .withTitle(QStringLiteral("Project 3")).withUid(QStringLiteral("uid-3")));
1662         data.createItem(GenTodo().withId(2).withParent(colId)
1663                                  .withTitle(QStringLiteral("Intermediate item 2")).withUid(QStringLiteral("uid-2"))
1664                                  .withParentUid(QStringLiteral("uid-3")));
1665         data.createItem(GenTodo().withId(1).withParent(colId)
1666                                  .withTitle(QStringLiteral("Item 1")).withUid(QStringLiteral("uid-1"))
1667                                  .withParentUid(QStringLiteral("uid-2")));
1668         data.createItem(GenTodo().withId(5).asProject().withParent(colId)
1669                                  .withTitle(QStringLiteral("Project 5")).withUid(QStringLiteral("uid-5")));
1670         data.createItem(GenTodo().withId(4).withParent(colId)
1671                                  .withTitle(QStringLiteral("Intermediate item 4")).withUid(QStringLiteral("uid-4"))
1672                                  .withParentUid(QStringLiteral("uid-5")));
1673 
1674         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1675 
1676         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1677         auto storage = createCachingStorage(data, cache);
1678         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1679                                                                              serializer,
1680                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1681                                                                              cache));
1682         auto task = serializer->createTaskFromItem(data.item(1));
1683 
1684         auto result = queries->findProject(task);
1685 
1686         QVERIFY(result);
1687         TestHelpers::waitForEmptyJobQueue();
1688         QCOMPARE(result->data().size(), 1);
1689         QCOMPARE(result->data().at(0)->name(), QStringLiteral("Project 3"));
1690 
1691         // WHEN
1692         data.modifyItem(GenTodo(data.item(1)).withParentUid(QStringLiteral("uid-4")));
1693 
1694         // THEN
1695         TestHelpers::waitForEmptyJobQueue();
1696         QCOMPARE(result->data().size(), 1);
1697         QCOMPARE(result->data().at(0)->name(), QStringLiteral("Project 5"));
1698     }
1699 
1700     void findProjectShouldReactToIntermediateParentChange()
1701     {
1702         // GIVEN
1703         AkonadiFakeData data;
1704 
1705         // One top level collection
1706         const Akonadi::Collection::Id colId = 42;
1707         data.createCollection(GenCollection().withId(colId).withRootAsParent().withTaskContent());
1708 
1709         // Three tasks in the collection (two being children of the first one)
1710         // 1->2->3 (project)  where 2 changes to 1->2->4 (project)
1711         data.createItem(GenTodo().withId(3).asProject().withParent(colId)
1712                                  .withTitle(QStringLiteral("Project 3")).withUid(QStringLiteral("uid-3")));
1713         data.createItem(GenTodo().withId(2).withParent(colId)
1714                                  .withTitle(QStringLiteral("Intermediate item 2")).withUid(QStringLiteral("uid-2"))
1715                                  .withParentUid(QStringLiteral("uid-3")));
1716         data.createItem(GenTodo().withId(1).withParent(colId)
1717                                  .withTitle(QStringLiteral("Item 1")).withUid(QStringLiteral("uid-1"))
1718                                  .withParentUid(QStringLiteral("uid-2")));
1719         data.createItem(GenTodo().withId(4).asProject().withParent(colId)
1720                                  .withTitle(QStringLiteral("Project 4")).withUid(QStringLiteral("uid-4")));
1721 
1722         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1723 
1724         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1725         auto storage = createCachingStorage(data, cache);
1726         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1727                                                                              serializer,
1728                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1729                                                                              cache));
1730         auto task = serializer->createTaskFromItem(data.item(1));
1731 
1732         auto result = queries->findProject(task);
1733 
1734         QVERIFY(result);
1735         TestHelpers::waitForEmptyJobQueue();
1736         QCOMPARE(result->data().size(), 1);
1737         QCOMPARE(result->data().at(0)->name(), QStringLiteral("Project 3"));
1738 
1739         // WHEN
1740         data.modifyItem(GenTodo(data.item(2)).withParentUid(QStringLiteral("uid-4")));
1741 
1742         // THEN
1743         TestHelpers::waitForEmptyJobQueue();
1744         QCOMPARE(result->data().size(), 1);
1745         QCOMPARE(result->data().at(0)->name(), QStringLiteral("Project 4"));
1746 
1747         // AND WHEN
1748         data.removeItem(GenTodo(data.item(2)));
1749 
1750         // THEN
1751         TestHelpers::waitForEmptyJobQueue();
1752         QCOMPARE(result->data().size(), 0);
1753     }
1754 
1755     void findProjectShouldReactToChildItemRemoved()
1756     {
1757         // GIVEN
1758         AkonadiFakeData data;
1759 
1760         // One top level collection
1761         const Akonadi::Collection::Id colId = 42;
1762         data.createCollection(GenCollection().withId(colId).withRootAsParent().withTaskContent());
1763 
1764         // Three task in the collection: 1->2(project)
1765         data.createItem(GenTodo().withId(2).asProject().withParent(colId)
1766                                  .withTitle(QStringLiteral("Project 2")).withUid(QStringLiteral("uid-2")));
1767         data.createItem(GenTodo().withId(1).withParent(colId)
1768                                  .withTitle(QStringLiteral("Item 1")).withUid(QStringLiteral("uid-1"))
1769                                  .withParentUid(QStringLiteral("uid-2")));
1770 
1771         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1772 
1773         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1774         auto storage = createCachingStorage(data, cache);
1775         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1776                                                                              serializer,
1777                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1778                                                                              cache));
1779         auto task = serializer->createTaskFromItem(data.item(1));
1780         auto result = queries->findProject(task);
1781         QVERIFY(result);
1782         TestHelpers::waitForEmptyJobQueue();
1783         QCOMPARE(result->data().size(), 1);
1784         QCOMPARE(result->data().at(0)->name(), QStringLiteral("Project 2"));
1785 
1786         // WHEN
1787         data.removeItem(Akonadi::Item(1));
1788 
1789         // THEN
1790         TestHelpers::waitForEmptyJobQueue();
1791         QCOMPARE(result->data().size(), 0);
1792     }
1793 
1794     void findContextsShouldLookInAllCollections()
1795     {
1796         // GIVEN
1797         AkonadiFakeData data;
1798 
1799         // One top level collection
1800         auto collection1 = GenCollection().withId(42).withRootAsParent().withTaskContent();
1801         data.createCollection(collection1);
1802         auto collection2 = GenCollection().withId(43).withRootAsParent().withTaskContent();
1803         data.createCollection(collection2);
1804 
1805         // One task in collection1, one context in collection1, one context in collection2
1806         data.createItem(GenTodo().withId(42).withParent(42)
1807                         .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1808                         .withContexts({ QStringLiteral("uid-43"), QStringLiteral("uid-44") }));
1809         data.createItem(GenTodo().withId(43).withParent(42).asContext()
1810                         .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
1811         data.createItem(GenTodo().withId(44).withParent(43).asContext()
1812                         .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")));
1813 
1814         // WHEN
1815         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1816 
1817         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1818         auto storage = createCachingStorage(data, cache);
1819         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1820                                                                              serializer,
1821                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1822                                                                              cache));
1823         auto task = serializer->createTaskFromItem(data.item(42));
1824         // populate cache for collection
1825         auto *fetchJob = storage->fetchItems(collection1, nullptr);
1826         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1827         fetchJob = storage->fetchItems(collection2, nullptr);
1828         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1829 
1830         auto result = queries->findContexts(task);
1831 
1832         // THEN
1833         QVERIFY(result);
1834         TestHelpers::waitForEmptyJobQueue();
1835         QCOMPARE(result->data().size(), 2);
1836         QCOMPARE(result->data().at(0)->name(), QStringLiteral("43"));
1837         QCOMPARE(result->data().at(1)->name(), QStringLiteral("44"));
1838 
1839         // Should not change anything
1840         result = queries->findContexts(task);
1841 
1842         QCOMPARE(result->data().size(), 2);
1843         QCOMPARE(result->data().at(0)->name(), QStringLiteral("43"));
1844         QCOMPARE(result->data().at(1)->name(), QStringLiteral("44"));
1845     }
1846 
1847     void findContextsShouldReactToRelationshipChange()
1848     {
1849         // GIVEN
1850         AkonadiFakeData data;
1851 
1852         // One top level collection
1853         auto collection1 = GenCollection().withId(42).withRootAsParent().withTaskContent();
1854         data.createCollection(collection1);
1855         auto collection2 = GenCollection().withId(43).withRootAsParent().withTaskContent();
1856         data.createCollection(collection2);
1857 
1858         // One task in collection1, one context in collection1, two contexts in collection2
1859         data.createItem(GenTodo().withId(42).withParent(42)
1860                         .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1861                         .withContexts({ QStringLiteral("uid-43"), QStringLiteral("uid-44") }));
1862         data.createItem(GenTodo().withId(43).withParent(42).asContext()
1863                         .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
1864         data.createItem(GenTodo().withId(44).withParent(43).asContext()
1865                         .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")));
1866         data.createItem(GenTodo().withId(45).withParent(43).asContext()
1867                         .withTitle(QStringLiteral("45")).withUid(QStringLiteral("uid-45")));
1868 
1869         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1870 
1871         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1872         auto storage = createCachingStorage(data, cache);
1873         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1874                                                                              serializer,
1875                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1876                                                                              cache));
1877         auto task = serializer->createTaskFromItem(data.item(42));
1878         // populate cache for collection
1879         auto *fetchJob = storage->fetchItems(collection1, nullptr);
1880         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1881         fetchJob = storage->fetchItems(collection2, nullptr);
1882         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1883 
1884         auto result = queries->findContexts(task);
1885 
1886         QVERIFY(result);
1887         TestHelpers::waitForEmptyJobQueue();
1888         QCOMPARE(result->data().size(), 2);
1889         QCOMPARE(result->data().at(0)->name(), QStringLiteral("43"));
1890         QCOMPARE(result->data().at(1)->name(), QStringLiteral("44"));
1891 
1892         // WHEN
1893         data.modifyItem(GenTodo(data.item(42)).withContexts({ QStringLiteral("uid-43"), QStringLiteral("uid-45") }));
1894 
1895         // THEN
1896         TestHelpers::waitForEmptyJobQueue();
1897         QCOMPARE(result->data().size(), 2);
1898         QCOMPARE(result->data().at(0)->name(), QStringLiteral("43"));
1899         QCOMPARE(result->data().at(1)->name(), QStringLiteral("45"));
1900 
1901         // WHEN
1902         data.modifyItem(GenTodo(data.item(42)).withContexts({ QStringLiteral("uid-45") }));
1903 
1904         // THEN
1905         TestHelpers::waitForEmptyJobQueue();
1906         QCOMPARE(result->data().size(), 1);
1907         QCOMPARE(result->data().at(0)->name(), QStringLiteral("45"));
1908 
1909         // WHEN
1910         data.modifyItem(GenTodo(data.item(42)).withContexts({}));
1911 
1912         // THEN
1913         TestHelpers::waitForEmptyJobQueue();
1914         QCOMPARE(result->data().size(), 0);
1915     }
1916 
1917     void findContextsShouldReactToItemRemoved()
1918     {
1919         // GIVEN
1920         AkonadiFakeData data;
1921 
1922         // One top level collection
1923         auto collection1 = GenCollection().withId(42).withRootAsParent().withTaskContent();
1924         data.createCollection(collection1);
1925         auto collection2 = GenCollection().withId(43).withRootAsParent().withTaskContent();
1926         data.createCollection(collection2);
1927 
1928         // One task in collection1, one context in collection1, one context in collection2
1929         data.createItem(GenTodo().withId(42).withParent(42)
1930                         .withTitle(QStringLiteral("42")).withUid(QStringLiteral("uid-42"))
1931                         .withContexts({ QStringLiteral("uid-43"), QStringLiteral("uid-44") }));
1932         data.createItem(GenTodo().withId(43).withParent(42).asContext()
1933                         .withTitle(QStringLiteral("43")).withUid(QStringLiteral("uid-43")));
1934         data.createItem(GenTodo().withId(44).withParent(43).asContext()
1935                         .withTitle(QStringLiteral("44")).withUid(QStringLiteral("uid-44")));
1936 
1937         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1938 
1939         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1940         auto storage = createCachingStorage(data, cache);
1941         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1942                                                                              serializer,
1943                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1944                                                                              cache));
1945         auto task = serializer->createTaskFromItem(data.item(42));
1946         // populate cache for collection
1947         auto *fetchJob = storage->fetchItems(collection1, nullptr);
1948         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1949         fetchJob = storage->fetchItems(collection2, nullptr);
1950         QVERIFY2(fetchJob->kjob()->exec(), qPrintable(fetchJob->kjob()->errorString()));
1951 
1952         auto result = queries->findContexts(task);
1953 
1954         QVERIFY(result);
1955         TestHelpers::waitForEmptyJobQueue();
1956         QCOMPARE(result->data().size(), 2);
1957         QCOMPARE(result->data().at(0)->name(), QStringLiteral("43"));
1958         QCOMPARE(result->data().at(1)->name(), QStringLiteral("44"));
1959 
1960         // WHEN
1961         data.removeItem(Akonadi::Item(42));
1962 
1963         // THEN
1964         TestHelpers::waitForEmptyJobQueue();
1965         QCOMPARE(result->data().size(), 0);
1966     }
1967 
1968     void shouldOnlyReturnTopLevelTasks()
1969     {
1970         // GIVEN
1971         AkonadiFakeData data;
1972 
1973         // One collection
1974         data.createCollection(GenCollection().withId(42).withRootAsParent().withTaskContent());
1975 
1976         // One empty project
1977         data.createItem(GenTodo().withId(1).asProject().withParent(42)
1978                                  .withTitle(QStringLiteral("Empty Project")).withUid(QStringLiteral("project-1")));
1979         // One real project
1980         data.createItem(GenTodo().withId(2).asProject().withParent(42)
1981                                  .withTitle(QStringLiteral("Real Project")).withUid(QStringLiteral("project-2")));
1982 
1983         // Two toplevel tasks in the second collection, one with a child
1984         data.createItem(GenTodo().withId(3).withParent(42).withTitle(QStringLiteral("43")).withUid("parent-43").withParentUid("project-2"));
1985         data.createItem(GenTodo().withId(4).withParent(42).withTitle(QStringLiteral("44")).withParentUid(QStringLiteral("2"))); // non-existing parent
1986         data.createItem(GenTodo().withId(5).withParent(42).withTitle(QStringLiteral("45")).withParentUid(QStringLiteral("parent-43"))); // existing parent
1987 
1988         // WHEN
1989         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
1990         auto cache = Akonadi::Cache::Ptr::create(serializer, Akonadi::MonitorInterface::Ptr(data.createMonitor()));
1991         auto storage = createCachingStorage(data, cache);
1992         QScopedPointer<Domain::TaskQueries> queries(new Akonadi::TaskQueries(storage,
1993                                                                              serializer,
1994                                                                              Akonadi::MonitorInterface::Ptr(data.createMonitor()),
1995                                                                              cache));
1996         auto result = queries->findTopLevel();
1997         result->data();
1998         result = queries->findTopLevel(); // Should not cause any problem or wrong data
1999 
2000         // THEN
2001         QVERIFY(result->data().isEmpty());
2002         TestHelpers::waitForEmptyJobQueue();
2003 
2004         QCOMPARE(result->data().size(), 2);
2005         QCOMPARE(result->data().at(0)->title(), QStringLiteral("43"));
2006         QCOMPARE(result->data().at(1)->title(), QStringLiteral("44"));
2007     }
2008 
2009 };
2010 
2011 ZANSHIN_TEST_MAIN(AkonadiTaskQueriesTest)
2012 
2013 #include "akonaditaskqueriestest.moc"