1 /*
2  * SPDX-FileCopyrightText: 2017 Kevin Ottens <ervin@kde.org>
3  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4 */
5 
6 
7 #include <testlib/qtest_zanshin.h>
8 
9 #include "akonadi/akonadicache.h"
10 #include "akonadi/akonadiserializer.h"
11 
12 #include "testlib/akonadifakemonitor.h"
13 #include "testlib/gencollection.h"
14 #include "testlib/gentodo.h"
15 
16 using namespace Testlib;
17 
18 class AkonadiCacheTest : public QObject
19 {
20     Q_OBJECT
21 
22 private slots:
shouldHaveDefaultState()23     void shouldHaveDefaultState()
24     {
25         // GIVEN
26         auto monitor = AkonadiFakeMonitor::Ptr::create();
27         auto cache = Akonadi::Cache::Ptr::create(Akonadi::SerializerInterface::Ptr(new Akonadi::Serializer), monitor);
28 
29         // THEN
30         QVERIFY(!cache->isCollectionListPopulated());
31         QVERIFY(cache->collections().isEmpty());
32     }
33 
shouldStoreCollectionsAndUpdate()34     void shouldStoreCollectionsAndUpdate()
35     {
36         // GIVEN
37         const auto noteCollection = Akonadi::Collection(GenCollection().withRootAsParent()
38                                                                        .withId(1)
39                                                                        .withName("notes")
40                                                                        .withNoteContent());
41         const auto taskCollection = Akonadi::Collection(GenCollection().withRootAsParent()
42                                                                        .withId(2)
43                                                                        .withName("tasks")
44                                                                        .withTaskContent());
45         const auto noteTaskCollection = Akonadi::Collection(GenCollection().withRootAsParent()
46                                                                            .withId(3)
47                                                                            .withName("tasks+notes")
48                                                                            .withTaskContent()
49                                                                            .withNoteContent());
50         const auto stuffCollection = Akonadi::Collection(GenCollection().withRootAsParent()
51                                                                         .withId(4)
52                                                                         .withName("stuff"));
53 
54         auto monitor = AkonadiFakeMonitor::Ptr::create();
55         auto cache = Akonadi::Cache::Ptr::create(Akonadi::Serializer::Ptr(new Akonadi::Serializer), monitor);
56 
57         // WHEN
58         cache->setCollections(Akonadi::Collection::List() << stuffCollection << noteTaskCollection
59                                                           << taskCollection << noteCollection);
60 
61         // THEN
62         QVERIFY(cache->isCollectionListPopulated());
63         QVERIFY(cache->isCollectionKnown(stuffCollection.id()));
64         QVERIFY(!cache->isCollectionPopulated(stuffCollection.id()));
65         QVERIFY(cache->items(stuffCollection).isEmpty());
66         QCOMPARE(cache->collections(),
67                  Akonadi::Collection::List() << noteTaskCollection << taskCollection);
68         QCOMPARE(cache->allCollections(),
69                  Akonadi::Collection::List() << stuffCollection << noteTaskCollection
70                  << taskCollection << noteCollection);
71         QCOMPARE(cache->collection(stuffCollection.id()), stuffCollection);
72         QCOMPARE(cache->collection(stuffCollection.id()).name(), stuffCollection.name());
73 
74         // WHEN
75         monitor->changeCollection(GenCollection(stuffCollection).withName("stuff2"));
76 
77         // THEN
78         QCOMPARE(cache->collection(stuffCollection.id()).name(), QStringLiteral("stuff2"));
79 
80         // WHEN
81         monitor->changeCollection(GenCollection(noteTaskCollection).withName("note+task2"));
82 
83         // THEN
84         QCOMPARE(cache->collection(noteTaskCollection.id()).name(), QStringLiteral("note+task2"));
85 
86         // WHEN
87         monitor->changeCollection(GenCollection(taskCollection).withName("task2"));
88 
89         // THEN
90         QCOMPARE(cache->collection(taskCollection.id()).name(), QStringLiteral("task2"));
91     }
92 
shouldHandleCollectionAdds_data()93     void shouldHandleCollectionAdds_data()
94     {
95         QTest::addColumn<Akonadi::Collection>("collection");
96         QTest::addColumn<bool>("seen");
97 
98         const auto none = Akonadi::Collection(GenCollection().withRootAsParent()
99                                                              .withId(2)
100                                                              .withName("collection"));
101         const auto task = Akonadi::Collection(GenCollection(none).withTaskContent());
102         const auto note = Akonadi::Collection(GenCollection(none).withNoteContent());
103         const auto taskNote = Akonadi::Collection(GenCollection(none).withNoteContent().withTaskContent());
104 
105         QTest::newRow("tasks vs none") << none << false;
106         QTest::newRow("tasks vs task") << task << true;
107         QTest::newRow("tasks vs note") << note << false;
108         QTest::newRow("tasks vs taskNote") << taskNote << true;
109     }
110 
shouldHandleCollectionAdds()111     void shouldHandleCollectionAdds()
112     {
113         // GIVEN
114         QFETCH(Akonadi::Collection, collection);
115 
116         auto monitor = AkonadiFakeMonitor::Ptr::create();
117         auto cache = Akonadi::Cache::Ptr::create(Akonadi::Serializer::Ptr(new Akonadi::Serializer), monitor);
118 
119         // WHEN
120         monitor->addCollection(collection);
121 
122         // THEN
123         QVERIFY(!cache->isCollectionListPopulated());
124         QVERIFY(cache->collections().isEmpty());
125         QCOMPARE(cache->collection(collection.id()), Akonadi::Collection());
126 
127         // WHEN
128         cache->setCollections(Akonadi::Collection::List());
129         monitor->addCollection(collection);
130 
131         // THEN
132         QVERIFY(cache->isCollectionListPopulated());
133         QFETCH(bool, seen);
134         if (seen) {
135             QVERIFY(!cache->collections().isEmpty());
136             QCOMPARE(cache->collection(collection.id()), collection);
137             QCOMPARE(cache->collection(collection.id()).name(), collection.name());
138         } else {
139             QVERIFY(cache->collections().isEmpty());
140             QCOMPARE(cache->collection(collection.id()), Akonadi::Collection());
141         }
142     }
143 
shouldHandleCollectionChanges()144     void shouldHandleCollectionChanges()
145     {
146         // GIVEN
147         const auto collection = Akonadi::Collection(GenCollection().withRootAsParent()
148                                                                    .withId(2)
149                                                                    .withName("tasks")
150                                                                    .withTaskContent());
151 
152         auto monitor = AkonadiFakeMonitor::Ptr::create();
153         auto cache = Akonadi::Cache::Ptr::create(Akonadi::Serializer::Ptr(new Akonadi::Serializer), monitor);
154         cache->setCollections(Akonadi::Collection::List() << collection);
155 
156         // WHEN
157         const auto collection2 = Akonadi::Collection(GenCollection().withRootAsParent()
158                                                                     .withId(2)
159                                                                     .withName("tasks2")
160                                                                     .withTaskContent());
161         monitor->changeCollection(collection2);
162 
163         // THEN
164         QCOMPARE(cache->collection(collection.id()).name(), QStringLiteral("tasks2"));
165     }
166 
shouldPopulateCollectionsWithItems()167     void shouldPopulateCollectionsWithItems()
168     {
169         // GIVEN
170         const auto taskCollection1 = Akonadi::Collection(GenCollection().withRootAsParent()
171                                                                         .withId(1)
172                                                                         .withName("tasks1")
173                                                                         .withTaskContent());
174         const auto items1 = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(1).withTitle("item1"))
175                                                   << Akonadi::Item(GenTodo().withId(2).withTitle("item2"));
176         const auto taskCollection2 = Akonadi::Collection(GenCollection().withRootAsParent()
177                                                                         .withId(2)
178                                                                         .withName("tasks2")
179                                                                         .withTaskContent());
180         const auto items2 = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(3).withTitle("item3"))
181                                                   << Akonadi::Item(GenTodo().withId(4).withTitle("item4"));
182 
183         auto monitor = AkonadiFakeMonitor::Ptr::create();
184         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
185         auto cache = Akonadi::Cache::Ptr::create(serializer, monitor);
186         cache->setCollections(Akonadi::Collection::List() << taskCollection1 << taskCollection2);
187 
188         // WHEN
189         cache->populateCollection(taskCollection1, items1);
190 
191         // THEN
192         QVERIFY(cache->isCollectionPopulated(taskCollection1.id()));
193         QCOMPARE(cache->items(taskCollection1), items1);
194         QCOMPARE(cache->item(items1.at(0).id()), items1.at(0));
195         QCOMPARE(cache->item(items1.at(1).id()), items1.at(1));
196 
197         // WHEN
198         cache->populateCollection(taskCollection2, items2);
199 
200         // THEN
201         QVERIFY(cache->isCollectionPopulated(taskCollection2.id()));
202         QCOMPARE(cache->items(taskCollection2), items2);
203         QCOMPARE(cache->item(items2.at(0).id()), items2.at(0));
204         QCOMPARE(cache->item(items2.at(1).id()), items2.at(1));
205     }
206 
shouldHandleCollectionRemoves()207     void shouldHandleCollectionRemoves()
208     {
209         // GIVEN
210         const auto collection1 = Akonadi::Collection(GenCollection().withRootAsParent()
211                                                                     .withId(1)
212                                                                     .withName("tasks1")
213                                                                     .withTaskContent());
214         const auto items1 = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(1).withTitle("item1"))
215                                                   << Akonadi::Item(GenTodo().withId(2).withTitle("item2"));
216         const auto collection2 = Akonadi::Collection(GenCollection().withRootAsParent()
217                                                                     .withId(2)
218                                                                     .withName("tasks2")
219                                                                     .withTaskContent());
220         const auto items2 = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(3).withTitle("item3"))
221                                                   << Akonadi::Item(GenTodo().withId(4).withTitle("item4"));
222 
223         auto monitor = AkonadiFakeMonitor::Ptr::create();
224         auto cache = Akonadi::Cache::Ptr::create(Akonadi::Serializer::Ptr(new Akonadi::Serializer), monitor);
225         cache->setCollections(Akonadi::Collection::List() << collection1 << collection2);
226         cache->populateCollection(collection1, items1);
227         cache->populateCollection(collection2, items2);
228 
229         // WHEN
230         monitor->removeCollection(collection1);
231 
232         // THEN
233         QVERIFY(!cache->isCollectionPopulated(collection1.id()));
234         QVERIFY(cache->items(collection1).isEmpty());
235         QCOMPARE(cache->item(items1.at(0).id()), Akonadi::Item());
236         QCOMPARE(cache->item(items1.at(1).id()), Akonadi::Item());
237 
238         QVERIFY(cache->isCollectionPopulated(collection2.id()));
239         QCOMPARE(cache->items(collection2), items2);
240         QCOMPARE(cache->item(items2.at(0).id()), items2.at(0));
241         QCOMPARE(cache->item(items2.at(1).id()), items2.at(1));
242     }
243 
shouldHandleItemChanges()244     void shouldHandleItemChanges()
245     {
246         // GIVEN
247         const auto collection1 = Akonadi::Collection(GenCollection().withRootAsParent()
248                                                                     .withId(1)
249                                                                     .withName("tasks1")
250                                                                     .withTaskContent());
251         const auto collection2 = Akonadi::Collection(GenCollection().withRootAsParent()
252                                                                     .withId(2)
253                                                                     .withName("tasks2")
254                                                                     .withTaskContent());
255         const auto collection3 = Akonadi::Collection(GenCollection().withRootAsParent()
256                                                                     .withId(3)
257                                                                     .withName("tasks3")
258                                                                     .withTaskContent());
259         const auto items = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(1).withParent(1).withContexts({"ctx-1"}).withTitle("item1"))
260                                                  << Akonadi::Item(GenTodo().withId(2).withParent(1).withContexts({"ctx-1"}).withTitle("item2"));
261         const auto item3 = Akonadi::Item(GenTodo().withId(3).withParent(1).withContexts({"ctx-1"}).withTitle("item3"));
262 
263 
264         auto monitor = AkonadiFakeMonitor::Ptr::create();
265         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
266         auto cache = Akonadi::Cache::Ptr::create(serializer, monitor);
267         cache->setCollections(Akonadi::Collection::List() << collection1 << collection2 << collection3);
268         cache->populateCollection(collection1, items);
269         cache->populateCollection(collection2, Akonadi::Item::List());
270 
271         // WHEN
272         monitor->changeItem(GenTodo(items.at(0)).withTitle("item1bis"));
273 
274         // THEN
275         auto todo = serializer->createTaskFromItem(cache->item(items.at(0).id()));
276         QCOMPARE(todo->title(), QStringLiteral("item1bis"));
277 
278         QVERIFY(cache->isCollectionPopulated(collection1.id()));
279         QVERIFY(cache->items(collection1).contains(items.at(0)));
280         QVERIFY(cache->isCollectionPopulated(collection2.id()));
281         QVERIFY(!cache->items(collection2).contains(items.at(0)));
282         QVERIFY(!cache->isCollectionPopulated(collection3.id()));
283         QVERIFY(!cache->items(collection3).contains(items.at(0)));
284 
285         // WHEN
286         monitor->changeItem(GenTodo(items.at(0)).withParent(2));
287 
288         // THEN
289         QVERIFY(cache->isCollectionPopulated(collection1.id()));
290         QVERIFY(!cache->items(collection1).contains(items.at(0)));
291         QVERIFY(cache->isCollectionPopulated(collection2.id()));
292         QVERIFY(cache->items(collection2).contains(items.at(0)));
293         QVERIFY(!cache->isCollectionPopulated(collection3.id()));
294         QVERIFY(!cache->items(collection3).contains(items.at(0)));
295 
296         // WHEN
297         monitor->changeItem(GenTodo(items.at(0)).withParent(3));
298 
299         // THEN
300         QVERIFY(cache->isCollectionPopulated(collection1.id()));
301         QVERIFY(!cache->items(collection1).contains(items.at(0)));
302         QVERIFY(cache->isCollectionPopulated(collection2.id()));
303         QVERIFY(!cache->items(collection2).contains(items.at(0)));
304         QVERIFY(!cache->isCollectionPopulated(collection3.id()));
305         QVERIFY(!cache->items(collection3).contains(items.at(0)));
306 
307         // WHEN
308         monitor->changeItem(GenTodo().withId(1).withParent(2).withContexts({"ctx-2"}).withTitle("item1"));
309 
310         // THEN
311         QVERIFY(cache->isCollectionPopulated(collection1.id()));
312         QVERIFY(!cache->items(collection1).contains(items.at(0)));
313         QVERIFY(cache->isCollectionPopulated(collection2.id()));
314         QVERIFY(cache->items(collection2).contains(items.at(0)));
315         QVERIFY(!cache->isCollectionPopulated(collection3.id()));
316         QVERIFY(!cache->items(collection3).contains(items.at(0)));
317 
318         // WHEN
319         monitor->changeItem(item3);
320 
321         // THEN
322         QVERIFY(cache->items(collection1).contains(item3));
323     }
324 
shouldHandleItemAdds()325     void shouldHandleItemAdds()
326     {
327         // GIVEN
328         const auto collection1 = Akonadi::Collection(GenCollection().withRootAsParent()
329                                                                     .withId(1)
330                                                                     .withName("tasks1")
331                                                                     .withTaskContent());
332         const auto collection2 = Akonadi::Collection(GenCollection().withRootAsParent()
333                                                      .withId(2)
334                                                      .withName("tasks2")
335                                                      .withTaskContent());
336         const auto item1 = Akonadi::Item(GenTodo().withId(1).withParent(1).withContexts({"ctx-1"}).withTitle("item1"));
337         const auto item2 = Akonadi::Item(GenTodo().withId(2).withParent(2).withContexts({"ctx-2"}).withTitle("item2"));
338 
339 
340         auto monitor = AkonadiFakeMonitor::Ptr::create();
341         auto serializer = Akonadi::Serializer::Ptr(new Akonadi::Serializer);
342         auto cache = Akonadi::Cache::Ptr::create(serializer, monitor);
343         cache->setCollections(Akonadi::Collection::List() << collection1 << collection2);
344         cache->populateCollection(collection1, Akonadi::Item::List());
345 
346         // WHEN
347         monitor->addItem(item1);
348 
349         // THEN
350         QVERIFY(cache->isCollectionPopulated(collection1.id()));
351         QVERIFY(!cache->items(collection1).isEmpty());
352         QCOMPARE(cache->items(collection1), Akonadi::Item::List() << item1);
353         QVERIFY(!cache->isCollectionPopulated(collection2.id()));
354         QVERIFY(cache->items(collection2).isEmpty());
355 
356         // WHEN
357         monitor->addItem(item2);
358 
359         // THEN
360         QVERIFY(cache->isCollectionPopulated(collection1.id()));
361         QVERIFY(!cache->items(collection1).isEmpty());
362         QCOMPARE(cache->items(collection1), Akonadi::Item::List() << item1);
363         QVERIFY(!cache->isCollectionPopulated(collection2.id()));
364         QVERIFY(cache->items(collection2).isEmpty());
365     }
366 
shouldHandleItemRemoves()367     void shouldHandleItemRemoves()
368     {
369         // GIVEN
370         const auto collection = Akonadi::Collection(GenCollection().withRootAsParent()
371                                                                    .withId(1)
372                                                                    .withName("tasks")
373                                                                    .withTaskContent());
374         const auto items = Akonadi::Item::List() << Akonadi::Item(GenTodo().withId(1).withTitle("item1"))
375                                                   << Akonadi::Item(GenTodo().withId(2).withTitle("item2"));
376 
377         auto monitor = AkonadiFakeMonitor::Ptr::create();
378         auto cache = Akonadi::Cache::Ptr::create(Akonadi::Serializer::Ptr(new Akonadi::Serializer), monitor);
379         cache->setCollections(Akonadi::Collection::List() << collection);
380         cache->populateCollection(collection, items);
381 
382         // WHEN
383         monitor->removeItem(items.at(0));
384 
385         // THEN
386         QVERIFY(cache->isCollectionPopulated(collection.id()));
387         QCOMPARE(cache->items(collection), Akonadi::Item::List() << items.at(1));
388         QCOMPARE(cache->item(items.at(0).id()), Akonadi::Item());
389         QCOMPARE(cache->item(items.at(1).id()), items.at(1));
390     }
391 };
392 
393 ZANSHIN_TEST_MAIN(AkonadiCacheTest)
394 
395 #include "akonadicachetest.moc"
396