1 /*
2 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
3 SPDX-FileCopyrightText: 2014 Rémi Benoit <r3m1.benoit@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6
7
8 #include <testlib/qtest_zanshin.h>
9
10 #include "akonadi/akonadiserializer.h"
11 #include "akonadi/akonadiapplicationselectedattribute.h"
12 #include "akonadi/akonaditimestampattribute.h"
13
14 #include <AkonadiCore/Akonadi/Collection>
15 #include <AkonadiCore/Akonadi/EntityDisplayAttribute>
16 #include <AkonadiCore/Akonadi/Item>
17 #include <KCalCore/Todo>
18 #if __has_include(<kcalcore_version.h>)
19 #include <kcalcore_version.h>
20 #else
21 #include <kcalendarcore_version.h>
22 #endif
23
24 Q_DECLARE_METATYPE(Akonadi::Item*)
25
26 using Akonadi::Serializer;
27
setTodoDates(KCalCore::Todo::Ptr todo,const QDate & start,const QDate & due)28 static void setTodoDates(KCalCore::Todo::Ptr todo, const QDate &start, const QDate &due) {
29 todo->setDtStart(QDateTime(start));
30 todo->setDtDue(QDateTime(due));
31 }
32
33 class AkonadiSerializerTest : public QObject
34 {
35 Q_OBJECT
36 private slots:
shouldKnowWhenAnObjectRepresentsACollection()37 void shouldKnowWhenAnObjectRepresentsACollection()
38 {
39 // GIVEN
40 Akonadi::Serializer serializer;
41 auto object = Akonadi::Serializer::QObjectPtr::create();
42 Akonadi::Collection collection(42);
43
44 // WHEN
45 // Nothing yet
46
47 // THEN
48 QVERIFY(!serializer.representsCollection(object, collection));
49
50 // WHEN
51 object->setProperty("collectionId", 42);
52
53 // THEN
54 QVERIFY(serializer.representsCollection(object, collection));
55
56 // WHEN
57 object->setProperty("collectionId", 43);
58
59 // THEN
60 QVERIFY(!serializer.representsCollection(object, collection));
61 }
62
shouldKnowWhenAnObjectRepresentsAnItem()63 void shouldKnowWhenAnObjectRepresentsAnItem()
64 {
65 // GIVEN
66 Akonadi::Serializer serializer;
67 auto object = Akonadi::Serializer::QObjectPtr::create();
68 Akonadi::Item item(42);
69
70 // WHEN
71 // Nothing yet
72
73 // THEN
74 QVERIFY(!serializer.representsItem(object, item));
75
76 // WHEN
77 object->setProperty("itemId", 42);
78
79 // THEN
80 QVERIFY(serializer.representsItem(object, item));
81
82 // WHEN
83 object->setProperty("itemId", 43);
84
85 // THEN
86 QVERIFY(!serializer.representsItem(object, item));
87 }
88
shouldKnowTaskItemUid_data()89 void shouldKnowTaskItemUid_data()
90 {
91 QTest::addColumn<Akonadi::Item>("item");
92 QTest::addColumn<QString>("expectedUid");
93
94 Akonadi::Item item1;
95 KCalCore::Todo::Ptr todo1(new KCalCore::Todo);
96 todo1->setUid(QString());
97 item1.setPayload<KCalCore::Todo::Ptr>(todo1);
98
99 Akonadi::Item item2;
100 KCalCore::Todo::Ptr todo2(new KCalCore::Todo);
101 todo2->setUid(QStringLiteral("1"));
102 item2.setPayload<KCalCore::Todo::Ptr>(todo2);
103
104 QTest::newRow("task without uid") << item1 << QString();
105 QTest::newRow("task with uid") << item2 << "1";
106 }
107
shouldKnowTaskItemUid()108 void shouldKnowTaskItemUid()
109 {
110 // GIVEN
111 QFETCH(Akonadi::Item, item);
112 QFETCH(QString, expectedUid);
113
114 // WHEN
115 Akonadi::Serializer serializer;
116 QString uid = serializer.itemUid(item);
117
118 // THEN
119 QCOMPARE(uid, expectedUid);
120 }
121
shouldCreateDataSourceFromCollection_data()122 void shouldCreateDataSourceFromCollection_data()
123 {
124 QTest::addColumn<QString>("name");
125 QTest::addColumn<QString>("iconName");
126 QTest::addColumn<QStringList>("mimeTypes");
127 QTest::addColumn<bool>("hasSelectedAttribute");
128 QTest::addColumn<bool>("isSelected");
129
130 const auto noteMimeTypes = QStringList() << QStringLiteral("text/x-vnd.akonadi.note");
131 const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo");
132 const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar");
133 const auto allMimeTypes = noteMimeTypes + taskMimeTypes + bogusMimeTypes;
134
135 QTest::newRow("nominal case") << "name" << "icon" << allMimeTypes << true << false;
136
137 QTest::newRow("only notes") << "name" << "icon" << noteMimeTypes << true << false;
138 QTest::newRow("only tasks") << "name" << "icon" << taskMimeTypes << true << false;
139 QTest::newRow("only bogus") << "name" << "icon" << bogusMimeTypes << true << false;
140
141 QTest::newRow("no selected attribute") << "name" << "icon" << allMimeTypes << false << false;
142 QTest::newRow("selected attribute (false)") << "name" << "icon" << allMimeTypes << true << false;
143 QTest::newRow("selected attribute (true)") << "name" << "icon" << allMimeTypes << true << true;
144
145 QTest::newRow("empty case") << QString() << QString() << QStringList() << false << false;
146 }
147
shouldCreateDataSourceFromCollection()148 void shouldCreateDataSourceFromCollection()
149 {
150 // GIVEN
151
152 // Data...
153 QFETCH(QString, name);
154 QFETCH(QString, iconName);
155 QFETCH(QStringList, mimeTypes);
156 QFETCH(bool, hasSelectedAttribute);
157 QFETCH(bool, isSelected);
158
159 Domain::DataSource::ContentTypes expectedContentTypes;
160 if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) {
161 expectedContentTypes |= Domain::DataSource::Tasks;
162 }
163
164 // ... stored in a collection
165 Akonadi::Collection collection(42);
166 collection.setContentMimeTypes(mimeTypes);
167 collection.setName(name);
168 auto displayAttribute = new Akonadi::EntityDisplayAttribute;
169 displayAttribute->setIconName(iconName);
170 collection.addAttribute(displayAttribute);
171 if (hasSelectedAttribute) {
172 auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute;
173 selectedAttribute->setSelected(isSelected);
174 collection.addAttribute(selectedAttribute);
175 }
176
177 // WHEN
178 Akonadi::Serializer serializer;
179 auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName);
180
181 // THEN
182 QCOMPARE(dataSource->name(), name);
183 QCOMPARE(dataSource->iconName(), iconName);
184 QCOMPARE(dataSource->contentTypes(), expectedContentTypes);
185 QCOMPARE(dataSource->isSelected(), !hasSelectedAttribute || isSelected);
186 QCOMPARE(dataSource->property("collectionId").value<Akonadi::Collection::Id>(), collection.id());
187 }
188
shouldCreateNullDataSourceFromInvalidCollection()189 void shouldCreateNullDataSourceFromInvalidCollection()
190 {
191 // GIVEN
192 Akonadi::Collection collection;
193
194 // WHEN
195 Akonadi::Serializer serializer;
196 auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName);
197
198 // THEN
199 QVERIFY(dataSource.isNull());
200 }
201
shouldUpdateDataSourceFromCollection_data()202 void shouldUpdateDataSourceFromCollection_data()
203 {
204 QTest::addColumn<QString>("updatedName");
205
206 QTest::newRow("no change") << "name";
207 QTest::newRow("changed") << "new name";
208 }
209
shouldUpdateDataSourceFromCollection()210 void shouldUpdateDataSourceFromCollection()
211 {
212 // GIVEN
213
214 // A collection...
215 Akonadi::Collection originalCollection(42);
216 originalCollection.setName(QStringLiteral("name"));
217
218 // ... deserialized as a data source
219 Akonadi::Serializer serializer;
220 auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName);
221
222 // WHEN
223
224 // Data...
225 QFETCH(QString, updatedName);
226
227 // ... in a new collection
228 Akonadi::Collection updatedCollection(42);
229 updatedCollection.setName(updatedName);
230
231 serializer.updateDataSourceFromCollection(dataSource, updatedCollection, Akonadi::SerializerInterface::BaseName);
232
233 // THEN
234 QCOMPARE(dataSource->name(), updatedName);
235 }
236
shouldNotUpdateDataSourceFromInvalidCollection()237 void shouldNotUpdateDataSourceFromInvalidCollection()
238 {
239 // GIVEN
240
241 // Data...
242 const QString name = QStringLiteral("name");
243
244 // ... stored in a collection...
245 Akonadi::Collection originalCollection(42);
246 originalCollection.setName(name);
247
248 // ... deserialized as a data source
249 Akonadi::Serializer serializer;
250 auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName);
251
252 // WHEN
253 Akonadi::Collection invalidCollection;
254 invalidCollection.setName(QStringLiteral("foo"));
255 serializer.updateDataSourceFromCollection(dataSource, invalidCollection, Akonadi::SerializerInterface::BaseName);
256
257 // THEN
258 QCOMPARE(dataSource->name(), name);
259 }
260
shouldNameDataSourceFromCollectionPathIfRequested()261 void shouldNameDataSourceFromCollectionPathIfRequested()
262 {
263 // GIVEN
264
265 // Data...
266 const QString name = QStringLiteral("name");
267 const QString parentName = QStringLiteral("parent");
268
269 // ... stored in a collection with a parent
270 Akonadi::Collection collection(42);
271 collection.setName(name);
272 Akonadi::Collection parentCollection(41);
273 parentCollection.setName(QStringLiteral("Foo"));
274 auto attribute = new Akonadi::EntityDisplayAttribute;
275 attribute->setDisplayName(parentName);
276 parentCollection.addAttribute(attribute);
277 collection.setParentCollection(parentCollection);
278
279 // WHEN
280 Akonadi::Serializer serializer;
281 auto dataSource1 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath);
282 auto dataSource2 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName);
283
284 // Give it another try with the root
285 parentCollection.setParentCollection(Akonadi::Collection::root());
286 collection.setParentCollection(parentCollection);
287 auto dataSource3 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath);
288 auto dataSource4 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName);
289
290 // THEN
291 QCOMPARE(dataSource1->name(), QString(parentName + " » " + name));
292 QCOMPARE(dataSource2->name(), name);
293 QCOMPARE(dataSource3->name(), QString(parentName + " » " + name));
294 QCOMPARE(dataSource4->name(), name);
295 }
296
shouldCreateCollectionFromDataSource_data()297 void shouldCreateCollectionFromDataSource_data()
298 {
299 QTest::addColumn<QString>("name");
300 QTest::addColumn<QString>("iconName");
301 QTest::addColumn<Domain::DataSource::ContentTypes>("contentTypes");
302 QTest::addColumn<bool>("isSelected");
303
304 const auto noType = Domain::DataSource::ContentTypes(Domain::DataSource::NoContent);
305 const auto taskType = Domain::DataSource::ContentTypes(Domain::DataSource::Tasks);
306
307 QTest::newRow("only tasks") << "name" << "icon-name" << taskType << true;
308 QTest::newRow("only nothing ;)") << "name" << "icon-name" << noType << true;
309
310 QTest::newRow("not selected") << "name" << "icon-name" << taskType << false;
311 QTest::newRow("selected") << "name" << "icon-name" << taskType << true;
312
313 QTest::newRow("empty case") << QString() << QString() << noType << true;
314 }
315
shouldCreateCollectionFromDataSource()316 void shouldCreateCollectionFromDataSource()
317 {
318 // GIVEN
319 const auto timestamp = QDateTime::currentMSecsSinceEpoch();
320
321 // Data...
322 QFETCH(QString, name);
323 QFETCH(QString, iconName);
324 QFETCH(Domain::DataSource::ContentTypes, contentTypes);
325 QFETCH(bool, isSelected);
326
327 QStringList mimeTypes;
328 if (contentTypes & Domain::DataSource::Tasks)
329 mimeTypes << QStringLiteral("application/x-vnd.akonadi.calendar.todo");
330
331
332 // ... stored in a data source
333 auto source = Domain::DataSource::Ptr::create();
334 source->setName(name);
335 source->setIconName(iconName);
336 source->setContentTypes(contentTypes);
337 source->setSelected(isSelected);
338 source->setProperty("collectionId", 42);
339
340 // WHEN
341 Akonadi::Serializer serializer;
342 auto collection = serializer.createCollectionFromDataSource(source);
343
344 // THEN
345 QCOMPARE(collection.id(), source->property("collectionId").value<Akonadi::Collection::Id>());
346 QVERIFY(collection.hasAttribute<Akonadi::ApplicationSelectedAttribute>());
347 QCOMPARE(collection.attribute<Akonadi::ApplicationSelectedAttribute>()->isSelected(), isSelected);
348 QVERIFY(collection.hasAttribute<Akonadi::TimestampAttribute>());
349 QVERIFY(collection.attribute<Akonadi::TimestampAttribute>()->timestamp() >= timestamp);
350 }
351
shouldVerifyIfCollectionIsSelected_data()352 void shouldVerifyIfCollectionIsSelected_data()
353 {
354 QTest::addColumn<QStringList>("mimeTypes");
355 QTest::addColumn<bool>("hasSelectedAttribute");
356 QTest::addColumn<bool>("isSelected");
357 QTest::addColumn<bool>("expectedSelected");
358
359 const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo");
360 const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar");
361 const auto allMimeTypes = taskMimeTypes + bogusMimeTypes;
362
363 QTest::newRow("nominal case") << allMimeTypes << true << false << false;
364
365 QTest::newRow("only tasks") << taskMimeTypes << true << false << false;
366 QTest::newRow("only bogus") << bogusMimeTypes << true << false << false;
367
368 QTest::newRow("selected, only tasks") << taskMimeTypes << true << true << true;
369 QTest::newRow("selected, only bogus") << bogusMimeTypes << true << true << false;
370
371 QTest::newRow("no selected attribute") << allMimeTypes << false << false << true;
372 QTest::newRow("selected attribute (false)") << allMimeTypes << true << false << false;
373 QTest::newRow("selected attribute (true)") << allMimeTypes << true << true << true;
374
375 QTest::newRow("empty case") << QStringList() << false << false << false;
376 }
377
shouldVerifyIfCollectionIsSelected()378 void shouldVerifyIfCollectionIsSelected()
379 {
380 // GIVEN
381 QFETCH(QStringList, mimeTypes);
382 QFETCH(bool, hasSelectedAttribute);
383 QFETCH(bool, isSelected);
384
385 Domain::DataSource::ContentTypes expectedContentTypes;
386 if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) {
387 expectedContentTypes |= Domain::DataSource::Tasks;
388 }
389
390 // ... stored in a collection
391 Akonadi::Collection collection(42);
392 collection.setContentMimeTypes(mimeTypes);
393 if (hasSelectedAttribute) {
394 auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute;
395 selectedAttribute->setSelected(isSelected);
396 collection.addAttribute(selectedAttribute);
397 }
398
399 // WHEN
400 Akonadi::Serializer serializer;
401
402 // THEN
403 QFETCH(bool, expectedSelected);
404 QCOMPARE(serializer.isSelectedCollection(collection), expectedSelected);
405 }
406
shouldVerifyCollectionContents_data()407 void shouldVerifyCollectionContents_data()
408 {
409 QTest::addColumn<QString>("mimeType");
410 QTest::addColumn<bool>("expectedTasks");
411
412 QTest::newRow("task collection") << "application/x-vnd.akonadi.calendar.todo" << true;
413 QTest::newRow("note collection") << "text/x-vnd.akonadi.note" << false;
414 }
415
shouldVerifyCollectionContents()416 void shouldVerifyCollectionContents()
417 {
418 // GIVEN
419
420 // Data...
421 QFETCH(QString, mimeType);
422
423 // ... stored in a collection
424 Akonadi::Collection collection(42);
425 collection.setContentMimeTypes(QStringList() << mimeType);
426
427 // WHEN
428 Akonadi::Serializer serializer;
429 QFETCH(bool, expectedTasks);
430
431 // THEN
432 QCOMPARE(serializer.isTaskCollection(collection), expectedTasks);
433 }
434
shouldCreateTaskFromItem_data()435 void shouldCreateTaskFromItem_data()
436 {
437 QTest::addColumn<QString>("summary");
438 QTest::addColumn<QString>("content");
439 QTest::addColumn<bool>("isDone");
440 QTest::addColumn<QDate>("doneDate");
441 QTest::addColumn<QDate>("startDate");
442 QTest::addColumn<QDate>("dueDate");
443 QTest::addColumn<QStringList>("contexts");
444
445 QTest::newRow("nominal case") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList();
446 QTest::newRow("done case") << "summary" << "content" << true << QDate(2013, 11, 30) << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList();
447 QTest::newRow("done without doneDate case") << "summary" << "content" << true << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList();
448 QTest::newRow("empty case") << QString() << QString() << false << QDate() << QDate() << QDate() << QStringList();
449 QTest::newRow("one_context") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList({"mycontext"});
450 QTest::newRow("two_contexts") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList({"c1", "c2"});
451 }
452
shouldCreateTaskFromItem()453 void shouldCreateTaskFromItem()
454 {
455 // GIVEN
456
457 // Data...
458 QFETCH(QString, summary);
459 QFETCH(QString, content);
460 QFETCH(bool, isDone);
461 QFETCH(QDate, doneDate);
462 QFETCH(QDate, startDate);
463 QFETCH(QDate, dueDate);
464 QFETCH(QStringList, contexts);
465
466 // ... stored in a todo...
467 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
468 todo->setSummary(summary);
469 todo->setDescription(content);
470
471 if (isDone)
472 todo->setCompleted(QDateTime(doneDate));
473 else
474 todo->setCompleted(isDone);
475
476 setTodoDates(todo, startDate, dueDate);
477 todo->setRelatedTo(QStringLiteral("my-uid"));
478
479 if (!contexts.isEmpty())
480 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contexts.join(','));
481
482 // ... as payload of an item
483 Akonadi::Item item;
484 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
485 item.setPayload<KCalCore::Todo::Ptr>(todo);
486
487 // which has a parent collection
488 Akonadi::Collection collection(43);
489 item.setParentCollection(collection);
490
491 // WHEN
492 Akonadi::Serializer serializer;
493 auto task = serializer.createTaskFromItem(item);
494
495 // THEN
496 QVERIFY(!task.isNull());
497 QCOMPARE(task->title(), summary);
498 QCOMPARE(task->text(), content);
499 QCOMPARE(task->isDone(), isDone);
500 QCOMPARE(task->doneDate(), doneDate);
501 QCOMPARE(task->startDate(), startDate);
502 QCOMPARE(task->dueDate(), dueDate);
503 QCOMPARE(task->property("todoUid").toString(), todo->uid());
504 QCOMPARE(task->property("relatedUid").toString(), todo->relatedTo());
505 QCOMPARE(task->property("contextUids").toStringList(), contexts);
506 QCOMPARE(task->property("itemId").toLongLong(), item.id());
507 QCOMPARE(task->property("parentCollectionId").toLongLong(), collection.id());
508 }
509
shouldCreateNullTaskFromInvalidItem()510 void shouldCreateNullTaskFromInvalidItem()
511 {
512 // GIVEN
513 Akonadi::Item item;
514
515 // WHEN
516 Akonadi::Serializer serializer;
517 auto task = serializer.createTaskFromItem(item);
518
519 // THEN
520 QVERIFY(task.isNull());
521 }
522
shouldCreateNullTaskFromProjectItem()523 void shouldCreateNullTaskFromProjectItem()
524 {
525 // GIVEN
526
527 // A todo with the project flag
528 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
529 todo->setSummary(QStringLiteral("foo"));
530 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
531
532 // ... as payload of an item
533 Akonadi::Item item;
534 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
535 item.setPayload<KCalCore::Todo::Ptr>(todo);
536
537 // WHEN
538 Akonadi::Serializer serializer;
539 auto task = serializer.createTaskFromItem(item);
540
541 // THEN
542 QVERIFY(task.isNull());
543 }
544
shouldUpdateTaskFromItem_data()545 void shouldUpdateTaskFromItem_data()
546 {
547 QTest::addColumn<QString>("updatedSummary");
548 QTest::addColumn<QString>("updatedContent");
549 QTest::addColumn<bool>("updatedDone");
550 QTest::addColumn<QDate>("updatedDoneDate");
551 QTest::addColumn<QDate>("updatedStartDate");
552 QTest::addColumn<QDate>("updatedDueDate");
553 QTest::addColumn<QString>("updatedRelated");
554 QTest::addColumn<QString>("updatedContexts");
555 QTest::addColumn<bool>("updatedRecurs");
556 QTest::addColumn<QByteArrayList>("updatedAttachmentData");
557 QTest::addColumn<QStringList>("updatedAttachmentUris");
558 QTest::addColumn<QStringList>("updatedAttachmentLabels");
559 QTest::addColumn<QStringList>("updatedAttachmentMimeTypes");
560 QTest::addColumn<QStringList>("updatedAttachmentIconNames");
561 QTest::addColumn<bool>("updatedRunning");
562
563 QTest::newRow("no change") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "my-uid" << "context1,context2" << false << QByteArrayList() << QStringList() << QStringList() << QStringList() << QStringList() << false;
564 QTest::newRow("changed") << "new summary" << "new content" << true << QDate(2013, 11, 28) << QDate(2013, 11, 25) << QDate(2014, 03, 02) << "my-new-uid" << "context2" << true << QByteArrayList({"foo", "# bar", QByteArray()}) << QStringList({QString(), QString(), "https://www.kde.org"}) << QStringList({"label1", "label2", "label3"}) << QStringList({"text/plain", "text/markdown", "text/html"}) << QStringList({"text-plain", "text-markdown", "text-html"}) << false;
565 QTest::newRow("set_to_running") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "my-uid" << "context1,context2" << false << QByteArrayList() << QStringList() << QStringList() << QStringList() << QStringList() << true;
566 }
567
shouldUpdateTaskFromItem()568 void shouldUpdateTaskFromItem()
569 {
570 // GIVEN
571
572 // A todo...
573 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
574 originalTodo->setSummary(QStringLiteral("summary"));
575 originalTodo->setDescription(QStringLiteral("content"));
576 originalTodo->setCompleted(false);
577 setTodoDates(originalTodo, QDate(2013, 11, 24), QDate(2014, 03, 01));
578
579 originalTodo->setRelatedTo(QStringLiteral("my-uid"));
580 originalTodo->setCustomProperty(Serializer::customPropertyAppName(),
581 Serializer::customPropertyContextList(),
582 QStringLiteral("context1,context2"));
583 #if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 11, 80)
584 KCalCore::Attendee originalAttendee(QStringLiteral("John Doe"),
585 QStringLiteral("j@d.com"),
586 true,
587 KCalCore::Attendee::Accepted);
588 #else
589 KCalCore::Attendee::Ptr originalAttendee(new KCalCore::Attendee(QStringLiteral("John Doe"),
590 QStringLiteral("j@d.com"),
591 true,
592 KCalCore::Attendee::Accepted));
593 #endif
594 originalTodo->addAttendee(originalAttendee);
595
596 // ... as payload of an item...
597 Akonadi::Item originalItem;
598 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
599 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
600
601 // ... which has a parent collection...
602 Akonadi::Collection originalCollection(43);
603 originalItem.setParentCollection(originalCollection);
604
605 // ... deserialized as a task
606 Akonadi::Serializer serializer;
607 auto task = serializer.createTaskFromItem(originalItem);
608
609 // WHEN
610
611 // Data...
612 QFETCH(QString, updatedSummary);
613 QFETCH(QString, updatedContent);
614 QFETCH(bool, updatedDone);
615 QFETCH(QDate, updatedDoneDate);
616 QFETCH(QDate, updatedStartDate);
617 QFETCH(QDate, updatedDueDate);
618 QFETCH(QString, updatedRelated);
619 QFETCH(QString, updatedContexts);
620 QFETCH(bool, updatedRecurs);
621 QFETCH(QByteArrayList, updatedAttachmentData);
622 QFETCH(QStringList, updatedAttachmentUris);
623 QFETCH(QStringList, updatedAttachmentLabels);
624 QFETCH(QStringList, updatedAttachmentMimeTypes);
625 QFETCH(QStringList, updatedAttachmentIconNames);
626 QFETCH(bool, updatedRunning);
627
628 // ... in a new todo...
629 KCalCore::Todo::Ptr updatedTodo(new KCalCore::Todo);
630 updatedTodo->setSummary(updatedSummary);
631 updatedTodo->setDescription(updatedContent);
632
633 if (updatedDone)
634 updatedTodo->setCompleted(QDateTime(updatedDoneDate));
635 else
636 updatedTodo->setCompleted(updatedDone);
637
638 setTodoDates(updatedTodo, updatedStartDate, updatedDueDate);
639 updatedTodo->setRelatedTo(updatedRelated);
640 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(),
641 Serializer::customPropertyContextList(),
642 updatedContexts);
643
644 if (updatedRecurs)
645 updatedTodo->recurrence()->setDaily(1);
646
647 for (int i = 0; i < updatedAttachmentData.size(); i++) {
648 #if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 11, 80)
649 KCalCore::Attachment attachment(QByteArray{});
650 if (!updatedAttachmentData.at(i).isEmpty())
651 attachment.setDecodedData(updatedAttachmentData.at(i));
652 else
653 attachment.setUri(updatedAttachmentUris.at(i));
654 attachment.setMimeType(updatedAttachmentMimeTypes.at(i));
655 attachment.setLabel(updatedAttachmentLabels.at(i));
656 #else
657 KCalCore::Attachment::Ptr attachment(new KCalCore::Attachment(QByteArray()));
658 if (!updatedAttachmentData.at(i).isEmpty())
659 attachment->setDecodedData(updatedAttachmentData.at(i));
660 else
661 attachment->setUri(updatedAttachmentUris.at(i));
662 attachment->setMimeType(updatedAttachmentMimeTypes.at(i));
663 attachment->setLabel(updatedAttachmentLabels.at(i));
664 #endif
665 updatedTodo->addAttachment(attachment);
666 }
667
668 if (updatedRunning) {
669 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning(), "1");
670 } else {
671 updatedTodo->removeCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning());
672 }
673
674 // ... as payload of a new item
675 Akonadi::Item updatedItem;
676 updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
677 updatedItem.setPayload<KCalCore::Todo::Ptr>(updatedTodo);
678
679 // ... which has a new parent collection
680 Akonadi::Collection updatedCollection(45);
681 updatedItem.setParentCollection(updatedCollection);
682
683 serializer.updateTaskFromItem(task, updatedItem);
684
685 // THEN
686 QCOMPARE(task->title(), updatedSummary);
687 QCOMPARE(task->text(), updatedContent);
688 QCOMPARE(task->isDone(), updatedDone);
689 QCOMPARE(task->doneDate(), updatedDoneDate);
690 QCOMPARE(task->startDate(), updatedStartDate);
691 QCOMPARE(task->dueDate(), updatedDueDate);
692 QCOMPARE(task->property("todoUid").toString(), updatedTodo->uid());
693 QCOMPARE(task->property("relatedUid").toString(), updatedTodo->relatedTo());
694 QCOMPARE(task->property("contextUids").toStringList(), updatedContexts.split(','));
695 QCOMPARE(task->property("itemId").toLongLong(), updatedItem.id());
696 QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id());
697 QCOMPARE(task->recurrence(), (updatedRecurs ? Domain::Task::RecursDaily : Domain::Task::NoRecurrence));
698 QCOMPARE(task->attachments().size(), updatedAttachmentData.size());
699 for (int i = 0; i < task->attachments().size(); i++) {
700 const auto attachment = task->attachments().at(i);
701 QCOMPARE(attachment.data(), updatedAttachmentData.at(i));
702 QCOMPARE(attachment.uri(), QUrl(updatedAttachmentUris.at(i)));
703 QCOMPARE(attachment.label(), updatedAttachmentLabels.at(i));
704 QCOMPARE(attachment.mimeType(), updatedAttachmentMimeTypes.at(i));
705 QCOMPARE(attachment.iconName(), updatedAttachmentIconNames.at(i));
706 }
707 QCOMPARE(task->isRunning(), updatedRunning);
708 }
709
shouldUpdateTaskRecurrenceFromItem_data()710 void shouldUpdateTaskRecurrenceFromItem_data()
711 {
712 QTest::addColumn<int>("todoRecurrence");
713 QTest::addColumn<Domain::Task::Recurrence>("expectedRecurrence");
714
715 QTest::newRow("none") << int(KCalCore::Recurrence::rNone) << Domain::Task::NoRecurrence;
716 QTest::newRow("minutely") << int(KCalCore::Recurrence::rMinutely) << Domain::Task::NoRecurrence;
717 QTest::newRow("hourly") << int(KCalCore::Recurrence::rHourly) << Domain::Task::NoRecurrence;
718 QTest::newRow("daily") << int(KCalCore::Recurrence::rDaily) << Domain::Task::RecursDaily;
719 QTest::newRow("weekly") << int(KCalCore::Recurrence::rWeekly) << Domain::Task::RecursWeekly;
720 QTest::newRow("monthly") << int(KCalCore::Recurrence::rMonthlyDay) << Domain::Task::RecursMonthly;
721 QTest::newRow("yearly") << int(KCalCore::Recurrence::rYearlyMonth) << Domain::Task::RecursYearly;
722 }
723
shouldUpdateTaskRecurrenceFromItem()724 void shouldUpdateTaskRecurrenceFromItem()
725 {
726 // GIVEN
727
728 // A todo...
729 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
730 todo->setSummary(QStringLiteral("summary"));
731
732 QFETCH(int, todoRecurrence);
733 switch (todoRecurrence) {
734 case KCalCore::Recurrence::rNone:
735 break;
736 case KCalCore::Recurrence::rMinutely:
737 todo->recurrence()->setMinutely(1);
738 break;
739 case KCalCore::Recurrence::rHourly:
740 todo->recurrence()->setHourly(1);
741 break;
742 case KCalCore::Recurrence::rDaily:
743 todo->recurrence()->setDaily(1);
744 break;
745 case KCalCore::Recurrence::rWeekly:
746 todo->recurrence()->setWeekly(1);
747 break;
748 case KCalCore::Recurrence::rMonthlyDay:
749 todo->recurrence()->setMonthly(1);
750 break;
751 case KCalCore::Recurrence::rYearlyMonth:
752 todo->recurrence()->setYearly(1);
753 break;
754 default:
755 qFatal("Shouldn't happen");
756 }
757
758 // ... as payload of an item...
759 Akonadi::Item item;
760 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
761 item.setPayload<KCalCore::Todo::Ptr>(todo);
762
763 // ... which has a parent collection...
764 Akonadi::Collection collection(43);
765 item.setParentCollection(collection);
766
767 // WHEN
768 // ... deserialized as a task
769 Akonadi::Serializer serializer;
770 auto task = serializer.createTaskFromItem(item);
771
772 // THEN
773 QFETCH(Domain::Task::Recurrence, expectedRecurrence);
774 QCOMPARE(task->recurrence(), expectedRecurrence);
775 }
776
shouldNotBreakRecurrenceDuringSerialization()777 void shouldNotBreakRecurrenceDuringSerialization()
778 {
779 // GIVEN
780
781 // Data...
782 const QDate today(QDate::currentDate());
783 const QDate doneDate(2013, 11, 20);
784 const QDate startDate(2013, 11, 10);
785
786 // ... stored in a todo...
787 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
788 todo->setSummary(QStringLiteral("summary"));
789 todo->setDtStart(QDateTime(startDate));
790 todo->recurrence()->setMonthly(1);
791
792 // ... as payload of an item...
793 Akonadi::Item item;
794 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
795 item.setPayload<KCalCore::Todo::Ptr>(todo);
796
797 // ... deserialized as a task
798 Akonadi::Serializer serializer;
799 auto task = serializer.createTaskFromItem(item);
800
801 // WHEN
802 // Task is marked done...
803 task->setDoneDate(doneDate);
804 task->setDone(true);
805
806 // and goes through serialization and back
807 const auto newItem = serializer.createItemFromTask(task);
808 serializer.updateTaskFromItem(task, newItem);
809
810 // THEN
811 QCOMPARE(task->recurrence(), Domain::Task::RecursMonthly);
812 QVERIFY(!task->isDone());
813 const QDate lastOccurrence(QDate(today.year(), today.month(), 10));
814 if (today.day() > 10)
815 QCOMPARE(task->startDate(), lastOccurrence.addMonths(1));
816 else
817 QCOMPARE(task->startDate(), lastOccurrence);
818 }
819
shouldNotUpdateTaskFromInvalidItem()820 void shouldNotUpdateTaskFromInvalidItem()
821 {
822 // GIVEN
823
824 // Data...
825 const QString summary = QStringLiteral("summary");
826 const QString content = QStringLiteral("content");
827 const bool isDone = true;
828 const QDate doneDate(2013, 11, 30);
829 const QDate startDate(2013, 11, 24);
830 const QDate dueDate(2014, 03, 01);
831
832 // ... stored in a todo...
833 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
834 originalTodo->setSummary(summary);
835 originalTodo->setDescription(content);
836
837 if (originalTodo)
838 originalTodo->setCompleted(QDateTime(doneDate));
839 else
840 originalTodo->setCompleted(isDone);
841 setTodoDates(originalTodo, startDate, dueDate);
842
843 // ... as payload of an item...
844 Akonadi::Item originalItem;
845 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
846 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
847
848 // ... deserialized as a task
849 Akonadi::Serializer serializer;
850 auto task = serializer.createTaskFromItem(originalItem);
851
852 // WHEN
853 Akonadi::Item invalidItem;
854 serializer.updateTaskFromItem(task, invalidItem);
855
856 // THEN
857 QCOMPARE(task->title(), summary);
858 QCOMPARE(task->text(), content);
859 QCOMPARE(task->isDone(), isDone);
860 QCOMPARE(task->doneDate(), doneDate);
861 QCOMPARE(task->startDate(), startDate);
862 QCOMPARE(task->dueDate(), dueDate);
863 QCOMPARE(task->property("itemId").toLongLong(), originalItem.id());
864 }
865
shouldNotUpdateTaskFromProjectItem()866 void shouldNotUpdateTaskFromProjectItem()
867 {
868 // GIVEN
869
870 // Data...
871 const QString summary = QStringLiteral("summary");
872 const QString content = QStringLiteral("content");
873 const bool isDone = true;
874 const QDate doneDate(2013, 11, 30);
875 const QDate startDate(2013, 11, 24);
876 const QDate dueDate(2014, 03, 01);
877
878 // ... stored in a todo...
879 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
880 originalTodo->setSummary(summary);
881 originalTodo->setDescription(content);
882
883 if (originalTodo)
884 originalTodo->setCompleted(QDateTime(doneDate));
885 else
886 originalTodo->setCompleted(isDone);
887 setTodoDates(originalTodo, startDate, dueDate);
888
889 // ... as payload of an item...
890 Akonadi::Item originalItem;
891 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
892 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
893
894 // ... deserialized as a task
895 Akonadi::Serializer serializer;
896 auto task = serializer.createTaskFromItem(originalItem);
897
898 // WHEN
899 // A todo with the project flag
900 KCalCore::Todo::Ptr projectTodo(new KCalCore::Todo);
901 projectTodo->setSummary(QStringLiteral("foo"));
902 projectTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
903
904 // ... as payload of an item
905 Akonadi::Item projectItem;
906 projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
907 projectItem.setPayload<KCalCore::Todo::Ptr>(projectTodo);
908 serializer.updateTaskFromItem(task, projectItem);
909
910 // THEN
911 QCOMPARE(task->title(), summary);
912 QCOMPARE(task->text(), content);
913 QCOMPARE(task->isDone(), isDone);
914 QCOMPARE(task->doneDate(), doneDate);
915 QCOMPARE(task->startDate(), startDate);
916 QCOMPARE(task->dueDate(), dueDate);
917 QCOMPARE(task->property("itemId").toLongLong(), originalItem.id());
918 }
919
shouldCreateItemFromTask_data()920 void shouldCreateItemFromTask_data()
921 {
922 QTest::addColumn<QString>("summary");
923 QTest::addColumn<QString>("content");
924 QTest::addColumn<bool>("isDone");
925 QTest::addColumn<QDate>("doneDate");
926 QTest::addColumn<QDate>("startDate");
927 QTest::addColumn<QDate>("dueDate");
928 QTest::addColumn<qint64>("itemId");
929 QTest::addColumn<qint64>("parentCollectionId");
930 QTest::addColumn<QString>("todoUid");
931 QTest::addColumn<Domain::Task::Recurrence>("recurrence");
932 QTest::addColumn<Domain::Task::Attachments>("attachments");
933 QTest::addColumn<bool>("running");
934 QTest::addColumn<QStringList>("contexts");
935
936 Domain::Task::Attachments attachments;
937
938 Domain::Task::Attachment dataAttachment;
939 dataAttachment.setData("foo");
940 dataAttachment.setLabel("dataAttachment");
941 dataAttachment.setMimeType("text/plain");
942 dataAttachment.setIconName("text-plain");
943 attachments.append(dataAttachment);
944
945 Domain::Task::Attachment uriAttachment;
946 uriAttachment.setUri(QUrl("https://www.kde.org"));
947 uriAttachment.setLabel("uriAttachment");
948 uriAttachment.setMimeType("text/html");
949 uriAttachment.setIconName("text-html");
950 attachments.append(uriAttachment);
951
952 QTest::newRow("nominal case (no id)") << "summary" << "content" << false << QDate()
953 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
954 << qint64(-1) << qint64(-1) << QString()
955 << Domain::Task::NoRecurrence
956 << attachments
957 << false
958 << QStringList();
959 QTest::newRow("nominal case (daily)") << "summary" << "content" << false << QDate()
960 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
961 << qint64(-1) << qint64(-1) << QString()
962 << Domain::Task::RecursDaily
963 << Domain::Task::Attachments()
964 << false
965 << QStringList();
966 QTest::newRow("nominal case (weekly)") << "summary" << "content" << false << QDate()
967 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
968 << qint64(-1) << qint64(-1) << QString()
969 << Domain::Task::RecursWeekly
970 << Domain::Task::Attachments()
971 << false
972 << QStringList();
973 QTest::newRow("nominal case (monthly)") << "summary" << "content" << false << QDate()
974 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
975 << qint64(-1) << qint64(-1) << QString()
976 << Domain::Task::RecursMonthly
977 << Domain::Task::Attachments()
978 << false
979 << QStringList();
980 QTest::newRow("nominal case (yearly)") << "summary" << "content" << false << QDate()
981 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
982 << qint64(-1) << qint64(-1) << QString()
983 << Domain::Task::RecursYearly
984 << Domain::Task::Attachments()
985 << false
986 << QStringList();
987 QTest::newRow("done case (no id)") << "summary" << "content" << true << QDate(2013, 11, 30)
988 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
989 << qint64(-1) << qint64(-1) << QString()
990 << Domain::Task::NoRecurrence
991 << Domain::Task::Attachments()
992 << false
993 << QStringList();
994 QTest::newRow("empty case (no id)") << QString() << QString() << false << QDate()
995 << QDate() << QDate()
996 << qint64(-1) << qint64(-1) << QString()
997 << Domain::Task::NoRecurrence
998 << Domain::Task::Attachments()
999 << false
1000 << QStringList();
1001 #if 0 // if we ever need time info, then we need a Task::setAllDay(bool) just like KCalCore::Todo has.
1002 QTest::newRow("nominal_with_time_info_noid") << "summary" << "content" << true << QDateTime(QDate(2015, 3, 1), QTime(1, 2, 3), Qt::UTC)
1003 << QDateTime(QDate(2013, 11, 24), QTime(0, 1, 2), Qt::UTC) << QDateTime(QDate(2016, 3, 1), QTime(4, 5, 6), Qt::UTC)
1004 << qint64(-1) << qint64(-1) << QString()
1005 << Domain::Task::NoRecurrence
1006 << Domain::Task::Attachments()
1007 << false
1008 << QStringList();
1009 #endif
1010
1011 QTest::newRow("nominal case (with id)") << "summary" << "content" << false << QDate()
1012 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
1013 << qint64(42) << qint64(43) << "my-uid"
1014 << Domain::Task::NoRecurrence
1015 << Domain::Task::Attachments()
1016 << false
1017 << QStringList();
1018 QTest::newRow("done case (with id)") << "summary" << "content" << true << QDate(2013, 11, 30)
1019 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
1020 << qint64(42) << qint64(43) << "my-uid"
1021 << Domain::Task::NoRecurrence
1022 << Domain::Task::Attachments()
1023 << false
1024 << QStringList();
1025 QTest::newRow("empty case (with id)") << QString() << QString() << false << QDate()
1026 << QDate() << QDate()
1027 << qint64(42) << qint64(43) << "my-uid"
1028 << Domain::Task::NoRecurrence
1029 << Domain::Task::Attachments()
1030 << false
1031 << QStringList();
1032 QTest::newRow("nominal case (running)") << "running" << QString() << false << QDate()
1033 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
1034 << qint64(-1) << qint64(-1) << QString()
1035 << Domain::Task::NoRecurrence
1036 << Domain::Task::Attachments()
1037 << true
1038 << QStringList();
1039 QTest::newRow("with_context") << "with_context" << QString() << false << QDate()
1040 << QDate(2013, 11, 24) << QDate(2014, 03, 01)
1041 << qint64(-1) << qint64(-1) << QString()
1042 << Domain::Task::NoRecurrence
1043 << Domain::Task::Attachments()
1044 << true
1045 << QStringList({"c1", "c2"});
1046 }
1047
shouldCreateItemFromTask()1048 void shouldCreateItemFromTask()
1049 {
1050 // GIVEN
1051
1052 // Data...
1053 QFETCH(QString, summary);
1054 QFETCH(QString, content);
1055 QFETCH(bool, isDone);
1056 QFETCH(QDate, doneDate);
1057 QFETCH(QDate, startDate);
1058 QFETCH(QDate, dueDate);
1059 QFETCH(qint64, itemId);
1060 QFETCH(qint64, parentCollectionId);
1061 QFETCH(QString, todoUid);
1062 QFETCH(Domain::Task::Recurrence, recurrence);
1063 QFETCH(Domain::Task::Attachments, attachments);
1064 QFETCH(bool, running);
1065 QFETCH(QStringList, contexts);
1066
1067 // ... stored in a task
1068 auto task = Domain::Task::Ptr::create();
1069 task->setTitle(summary);
1070 task->setText(content);
1071 task->setDone(isDone);
1072 task->setDoneDate(doneDate);
1073 task->setStartDate(startDate);
1074 task->setDueDate(dueDate);
1075 task->setRecurrence(recurrence);
1076 task->setAttachments(attachments);
1077 task->setRunning(running);
1078
1079 if (itemId > 0)
1080 task->setProperty("itemId", itemId);
1081
1082 if (parentCollectionId > 0)
1083 task->setProperty("parentCollectionId", parentCollectionId);
1084
1085 if (!todoUid.isEmpty())
1086 task->setProperty("todoUid", todoUid);
1087
1088 task->setProperty("relatedUid", "parent-uid");
1089 task->setProperty("contextUids", contexts);
1090
1091 // WHEN
1092 Akonadi::Serializer serializer;
1093 auto item = serializer.createItemFromTask(task);
1094
1095 // THEN
1096 QCOMPARE(item.mimeType(), KCalCore::Todo::todoMimeType());
1097
1098 QCOMPARE(item.isValid(), itemId > 0);
1099 if (itemId > 0) {
1100 QCOMPARE(item.id(), itemId);
1101 }
1102
1103 QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0);
1104 if (parentCollectionId > 0) {
1105 QCOMPARE(item.parentCollection().id(), parentCollectionId);
1106 }
1107
1108 auto todo = item.payload<KCalCore::Todo::Ptr>();
1109 QCOMPARE(todo->summary(), summary);
1110 QCOMPARE(todo->description(), content);
1111 QCOMPARE(todo->isCompleted(), isDone);
1112 QCOMPARE(todo->completed().toLocalTime().date(), doneDate);
1113 QCOMPARE(todo->dtStart().toLocalTime().date(), startDate);
1114 QCOMPARE(todo->dtDue().toLocalTime().date(), dueDate);
1115 if (todo->dtStart().isValid()) {
1116 QCOMPARE(int(todo->dtStart().timeSpec()), int(Qt::LocalTime));
1117 }
1118 QVERIFY(todo->allDay()); // this is always true currently...
1119 const ushort expectedRecurrence = recurrence == Domain::Task::NoRecurrence ? KCalCore::Recurrence::rNone
1120 : recurrence == Domain::Task::RecursDaily ? KCalCore::Recurrence::rDaily
1121 : recurrence == Domain::Task::RecursWeekly ? KCalCore::Recurrence::rWeekly
1122 : recurrence == Domain::Task::RecursMonthly ? KCalCore::Recurrence::rMonthlyDay
1123 : recurrence == Domain::Task::RecursYearly ? KCalCore::Recurrence::rYearlyMonth
1124 : KCalCore::Recurrence::rNone; // Shouldn't happen though
1125 QCOMPARE(todo->recurrence()->recurrenceType(), expectedRecurrence);
1126 if (recurrence != Domain::Task::NoRecurrence)
1127 QCOMPARE(todo->recurrence()->frequency(), 1);
1128
1129 QCOMPARE(todo->attachments().size(), attachments.size());
1130 for (int i = 0; i < attachments.size(); i++) {
1131 auto attachment = todo->attachments().at(i);
1132 #if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 11, 80)
1133 QCOMPARE(attachment.isUri(), attachments.at(i).isUri());
1134 QCOMPARE(QUrl(attachment.uri()), attachments.at(i).uri());
1135 QCOMPARE(attachment.decodedData(), attachments.at(i).data());
1136 QCOMPARE(attachment.label(), attachments.at(i).label());
1137 QCOMPARE(attachment.mimeType(), attachments.at(i).mimeType());
1138 #else
1139 QCOMPARE(attachment->isUri(), attachments.at(i).isUri());
1140 QCOMPARE(QUrl(attachment->uri()), attachments.at(i).uri());
1141 QCOMPARE(attachment->decodedData(), attachments.at(i).data());
1142 QCOMPARE(attachment->label(), attachments.at(i).label());
1143 QCOMPARE(attachment->mimeType(), attachments.at(i).mimeType());
1144 #endif
1145 }
1146
1147 if (!todoUid.isEmpty()) {
1148 QCOMPARE(todo->uid(), todoUid);
1149 }
1150
1151 QCOMPARE(todo->relatedTo(), QStringLiteral("parent-uid"));
1152 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning()), running ? QStringLiteral("1") : QString());
1153 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), contexts.join(','));
1154 }
1155
shouldVerifyIfAnItemIsATaskChild_data()1156 void shouldVerifyIfAnItemIsATaskChild_data()
1157 {
1158 QTest::addColumn<Domain::Task::Ptr>("task");
1159 QTest::addColumn<Akonadi::Item>("item");
1160 QTest::addColumn<bool>("isParent");
1161
1162 // Create task
1163 const QString summary = QStringLiteral("summary");
1164 const QString content = QStringLiteral("content");
1165 const bool isDone = true;
1166 const QDate doneDate(QDate(2013, 11, 30));
1167 const QDate startDate(QDate(2013, 11, 24));
1168 const QDate dueDate(QDate(2014, 03, 01));
1169
1170 // ... create a task
1171 Domain::Task::Ptr task(new Domain::Task);
1172 task->setTitle(summary);
1173 task->setText(content);
1174 task->setDone(isDone);
1175 task->setDoneDate(doneDate);
1176 task->setStartDate(startDate);
1177 task->setDueDate(dueDate);
1178 task->setProperty("todoUid", "1");
1179
1180 // Create Child item
1181 KCalCore::Todo::Ptr childTodo(new KCalCore::Todo);
1182 childTodo->setSummary(summary);
1183 childTodo->setDescription(content);
1184
1185 if (isDone)
1186 childTodo->setCompleted(QDateTime(doneDate));
1187 else
1188 childTodo->setCompleted(isDone);
1189
1190 setTodoDates(childTodo, startDate, dueDate);
1191
1192 Akonadi::Item childItem;
1193 childItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1194 childItem.setPayload<KCalCore::Todo::Ptr>(childTodo);
1195
1196 QTest::newRow("without parent") << task << childItem << false;
1197
1198 // Create Child Item with parent
1199 KCalCore::Todo::Ptr childTodo2(new KCalCore::Todo);
1200 childTodo2->setSummary(summary);
1201 childTodo2->setDescription(content);
1202
1203 if (isDone)
1204 childTodo2->setCompleted(QDateTime(doneDate));
1205 else
1206 childTodo2->setCompleted(isDone);
1207 setTodoDates(childTodo2, startDate, dueDate);
1208 childTodo2->setRelatedTo(QStringLiteral("1"));
1209
1210 Akonadi::Item childItem2;
1211 childItem2.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1212 childItem2.setPayload<KCalCore::Todo::Ptr>(childTodo2);
1213
1214 QTest::newRow("with parent") << task << childItem2 << true;
1215
1216 Domain::Task::Ptr invalidTask(new Domain::Task);
1217 QTest::newRow("with invalid task") << invalidTask << childItem << false;
1218
1219 Akonadi::Item invalidItem;
1220 QTest::newRow("with invalid item") << task << invalidItem << false;
1221
1222 }
1223
shouldVerifyIfAnItemIsATaskChild()1224 void shouldVerifyIfAnItemIsATaskChild()
1225 {
1226 // GIVEN
1227 QFETCH(Domain::Task::Ptr, task);
1228 QFETCH(Akonadi::Item, item);
1229 QFETCH(bool, isParent);
1230
1231 // WHEN
1232 Akonadi::Serializer serializer;
1233 bool value = serializer.isTaskChild(task, item);
1234
1235 // THEN
1236 QCOMPARE(value, isParent);
1237 }
1238
shouldRetrieveRelatedUidFromItem_data()1239 void shouldRetrieveRelatedUidFromItem_data()
1240 {
1241 QTest::addColumn<Akonadi::Item>("item");
1242 QTest::addColumn<QString>("expectedUid");
1243
1244 Akonadi::Item item1;
1245 KCalCore::Todo::Ptr todo1(new KCalCore::Todo);
1246 item1.setPayload<KCalCore::Todo::Ptr>(todo1);
1247
1248 Akonadi::Item item2;
1249 KCalCore::Todo::Ptr todo2(new KCalCore::Todo);
1250 todo2->setRelatedTo(QStringLiteral("1"));
1251 item2.setPayload<KCalCore::Todo::Ptr>(todo2);
1252
1253 QTest::newRow("task without related") << item1 << QString();
1254 QTest::newRow("task with related") << item2 << "1";
1255 }
1256
shouldRetrieveRelatedUidFromItem()1257 void shouldRetrieveRelatedUidFromItem()
1258 {
1259 // GIVEN
1260 QFETCH(Akonadi::Item, item);
1261 QFETCH(QString, expectedUid);
1262
1263 // WHEN
1264 Akonadi::Serializer serializer;
1265 QString uid = serializer.relatedUidFromItem(item);
1266
1267 // THEN
1268 QCOMPARE(uid, expectedUid);
1269 }
1270
shouldCreateNoteFromItem_data()1271 void shouldCreateNoteFromItem_data()
1272 {
1273 QTest::addColumn<QString>("title");
1274 QTest::addColumn<QString>("text");
1275 QTest::addColumn<QString>("relatedUid");
1276
1277 QTest::newRow("nominal case (no related)") << "A note title" << "A note content.\nWith two lines." << QString();
1278 QTest::newRow("nominal case (with related)") << "A note title" << "A note content.\nWith two lines." << "parent-uid";
1279 QTest::newRow("trailing new lines") << "A note title" << "Empty lines at the end.\n\n\n" << QString();
1280 QTest::newRow("empty case") << QString() << QString() << QString();
1281 }
1282
shouldCreateProjectFromItem_data()1283 void shouldCreateProjectFromItem_data()
1284 {
1285 QTest::addColumn<QString>("summary");
1286
1287 QTest::newRow("nominal case") << "summary";
1288 QTest::newRow("empty case") << QString();
1289 }
1290
shouldCreateProjectFromItem()1291 void shouldCreateProjectFromItem()
1292 {
1293 // GIVEN
1294
1295 // Data...
1296 QFETCH(QString, summary);
1297
1298 // ... stored in a todo...
1299 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1300 todo->setSummary(summary);
1301 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1302 QVERIFY(!todo->uid().isEmpty());
1303
1304 // ... as payload of an item
1305 Akonadi::Item item(42);
1306 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1307 item.setPayload<KCalCore::Todo::Ptr>(todo);
1308
1309 // which has a parent collection
1310 Akonadi::Collection collection(43);
1311 item.setParentCollection(collection);
1312
1313 // WHEN
1314 Akonadi::Serializer serializer;
1315 Domain::Project::Ptr project = serializer.createProjectFromItem(item);
1316
1317 // THEN
1318 QCOMPARE(project->name(), summary);
1319 QCOMPARE(project->property("itemId").toLongLong(), item.id());
1320 QCOMPARE(project->property("parentCollectionId").toLongLong(), collection.id());
1321 QCOMPARE(project->property("todoUid").toString(), todo->uid());
1322 }
1323
shouldCreateNullProjectFromInvalidItem()1324 void shouldCreateNullProjectFromInvalidItem()
1325 {
1326 // GIVEN
1327 Akonadi::Item item;
1328
1329 // WHEN
1330 Akonadi::Serializer serializer;
1331 Domain::Project::Ptr project = serializer.createProjectFromItem(item);
1332
1333 // THEN
1334 QVERIFY(project.isNull());
1335 }
1336
shouldCreateNullProjectFromTaskItem()1337 void shouldCreateNullProjectFromTaskItem()
1338 {
1339 // GIVEN
1340
1341 // A todo without the project flag
1342 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1343 todo->setSummary(QStringLiteral("foo"));
1344
1345 // ... as payload of an item
1346 Akonadi::Item item;
1347 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1348 item.setPayload<KCalCore::Todo::Ptr>(todo);
1349
1350 // WHEN
1351 Akonadi::Serializer serializer;
1352 Domain::Project::Ptr project = serializer.createProjectFromItem(item);
1353
1354 // THEN
1355 QVERIFY(project.isNull());
1356 }
1357
shouldUpdateProjectFromItem_data()1358 void shouldUpdateProjectFromItem_data()
1359 {
1360 QTest::addColumn<QString>("updatedSummary");
1361
1362 QTest::newRow("no change") << "summary";
1363 QTest::newRow("changed") << "new summary";
1364 }
1365
shouldUpdateProjectFromItem()1366 void shouldUpdateProjectFromItem()
1367 {
1368 // GIVEN
1369
1370 // A todo...
1371 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
1372 originalTodo->setSummary(QStringLiteral("summary"));
1373 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1374
1375 // ... as payload of an item...
1376 Akonadi::Item originalItem(42);
1377 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1378 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
1379
1380 // ... which has a parent collection...
1381 Akonadi::Collection originalCollection(43);
1382 originalItem.setParentCollection(originalCollection);
1383
1384 // ... deserialized as a project
1385 Akonadi::Serializer serializer;
1386 auto project = serializer.createProjectFromItem(originalItem);
1387
1388 // WHEN
1389
1390 // Data...
1391 QFETCH(QString, updatedSummary);
1392
1393 // ... in a new todo...
1394 KCalCore::Todo::Ptr updatedTodo(new KCalCore::Todo);
1395 updatedTodo->setSummary(updatedSummary);
1396 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1397 QVERIFY(!updatedTodo->uid().isEmpty());
1398
1399 // ... as payload of a new item
1400 Akonadi::Item updatedItem(44);
1401 updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1402 updatedItem.setPayload<KCalCore::Todo::Ptr>(updatedTodo);
1403
1404 // ... which has a new parent collection
1405 Akonadi::Collection updatedCollection(45);
1406 updatedItem.setParentCollection(updatedCollection);
1407
1408 serializer.updateProjectFromItem(project, updatedItem);
1409
1410 // THEN
1411 QCOMPARE(project->name(), updatedSummary);
1412 QCOMPARE(project->property("itemId").toLongLong(), updatedItem.id());
1413 QCOMPARE(project->property("parentCollectionId").toLongLong(), updatedCollection.id());
1414 QCOMPARE(project->property("todoUid").toString(), updatedTodo->uid());
1415 }
1416
shouldNotUpdateProjectFromInvalidItem()1417 void shouldNotUpdateProjectFromInvalidItem()
1418 {
1419 // GIVEN
1420
1421 // Data...
1422 const QString summary = QStringLiteral("summary");
1423
1424 // ... stored in a todo...
1425 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
1426 originalTodo->setSummary(summary);
1427 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1428
1429 // ... as payload of an item...
1430 Akonadi::Item originalItem;
1431 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1432 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
1433
1434 // ... deserialized as a project
1435 Akonadi::Serializer serializer;
1436 auto project = serializer.createProjectFromItem(originalItem);
1437
1438 // WHEN
1439 Akonadi::Item invalidItem;
1440 serializer.updateProjectFromItem(project, invalidItem);
1441
1442 // THEN
1443 QCOMPARE(project->name(), summary);
1444 }
1445
shouldNotUpdateProjectFromTaskItem()1446 void shouldNotUpdateProjectFromTaskItem()
1447 {
1448 // GIVEN
1449
1450 // Data...
1451 const QString summary = QStringLiteral("summary");
1452
1453 // ... stored in a todo...
1454 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
1455 originalTodo->setSummary(summary);
1456 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1457
1458 // ... as payload of an item...
1459 Akonadi::Item originalItem;
1460 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1461 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
1462
1463 // ... deserialized as a project
1464 Akonadi::Serializer serializer;
1465 auto project = serializer.createProjectFromItem(originalItem);
1466
1467 // WHEN
1468 // A todo without the project flag
1469 KCalCore::Todo::Ptr projectTodo(new KCalCore::Todo);
1470 projectTodo->setSummary(QStringLiteral("foo"));
1471
1472 // ... as payload of an item
1473 Akonadi::Item projectItem;
1474 projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1475 projectItem.setPayload<KCalCore::Todo::Ptr>(projectTodo);
1476 serializer.updateProjectFromItem(project, projectItem);
1477
1478 // THEN
1479 QCOMPARE(project->name(), summary);
1480 }
1481
shouldCreateItemFromProject_data()1482 void shouldCreateItemFromProject_data()
1483 {
1484 QTest::addColumn<QString>("summary");
1485 QTest::addColumn<qint64>("itemId");
1486 QTest::addColumn<qint64>("parentCollectionId");
1487
1488 QTest::newRow("nominal case (no id)") << "summary" << qint64(-1) << qint64(-1);
1489 QTest::newRow("empty case (no id)") << QString() << qint64(-1) << qint64(-1);
1490
1491 QTest::newRow("nominal case (with id)") << "summary" << qint64(42) << qint64(43);
1492 QTest::newRow("empty case (with id)") << QString() << qint64(42) << qint64(43);
1493 }
1494
shouldCreateItemFromProject()1495 void shouldCreateItemFromProject()
1496 {
1497 // GIVEN
1498
1499 // Data...
1500 QFETCH(QString, summary);
1501 QFETCH(qint64, itemId);
1502 QFETCH(qint64, parentCollectionId);
1503 const QString todoUid = QStringLiteral("test-uid");
1504
1505 // ... stored in a project
1506 auto project = Domain::Project::Ptr::create();
1507 project->setName(summary);
1508 project->setProperty("todoUid", todoUid);
1509
1510 if (itemId > 0)
1511 project->setProperty("itemId", itemId);
1512
1513 if (parentCollectionId > 0)
1514 project->setProperty("parentCollectionId", parentCollectionId);
1515
1516 // WHEN
1517 Akonadi::Serializer serializer;
1518 auto item = serializer.createItemFromProject(project);
1519
1520 // THEN
1521 QCOMPARE(item.mimeType(), KCalCore::Todo::todoMimeType());
1522
1523 QCOMPARE(item.isValid(), itemId > 0);
1524 if (itemId > 0) {
1525 QCOMPARE(item.id(), itemId);
1526 }
1527
1528 QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0);
1529 if (parentCollectionId > 0) {
1530 QCOMPARE(item.parentCollection().id(), parentCollectionId);
1531 }
1532
1533 auto todo = item.payload<KCalCore::Todo::Ptr>();
1534 QCOMPARE(todo->summary(), summary);
1535 QCOMPARE(todo->uid(), todoUid);
1536 QVERIFY(!todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject()).isEmpty());
1537 }
1538
shouldVerifyIfAnItemIsAProjectChild_data()1539 void shouldVerifyIfAnItemIsAProjectChild_data()
1540 {
1541 QTest::addColumn<Domain::Project::Ptr>("project");
1542 QTest::addColumn<Akonadi::Item>("item");
1543 QTest::addColumn<bool>("isParent");
1544
1545 // Create project
1546 auto project = Domain::Project::Ptr::create();
1547 project->setName(QStringLiteral("project"));
1548 project->setProperty("todoUid", "1");
1549
1550 // Create unrelated todo
1551 auto unrelatedTodo = KCalCore::Todo::Ptr::create();
1552 unrelatedTodo->setSummary(QStringLiteral("summary"));
1553 Akonadi::Item unrelatedTodoItem;
1554 unrelatedTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1555 unrelatedTodoItem.setPayload<KCalCore::Todo::Ptr>(unrelatedTodo);
1556
1557 QTest::newRow("unrelated todo") << project << unrelatedTodoItem << false;
1558
1559 // Create child todo
1560 auto childTodo = KCalCore::Todo::Ptr::create();
1561 childTodo->setSummary(QStringLiteral("summary"));
1562 childTodo->setRelatedTo(QStringLiteral("1"));
1563 Akonadi::Item childTodoItem;
1564 childTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1565 childTodoItem.setPayload<KCalCore::Todo::Ptr>(childTodo);
1566
1567 QTest::newRow("child todo") << project << childTodoItem << true;
1568
1569 auto invalidProject = Domain::Project::Ptr::create();
1570 QTest::newRow("invalid project") << invalidProject << unrelatedTodoItem << false;
1571
1572 Akonadi::Item invalidItem;
1573 QTest::newRow("invalid item") << project << invalidItem << false;
1574
1575 }
1576
shouldVerifyIfAnItemIsAProjectChild()1577 void shouldVerifyIfAnItemIsAProjectChild()
1578 {
1579 // GIVEN
1580 QFETCH(Domain::Project::Ptr, project);
1581 QFETCH(Akonadi::Item, item);
1582 QFETCH(bool, isParent);
1583
1584 // WHEN
1585 Akonadi::Serializer serializer;
1586 bool value = serializer.isProjectChild(project, item);
1587
1588 // THEN
1589 QCOMPARE(value, isParent);
1590 }
1591
shouldUpdateItemParent_data()1592 void shouldUpdateItemParent_data()
1593 {
1594 QTest::addColumn<Akonadi::Item>("item");
1595 QTest::addColumn<Domain::Task::Ptr>("parent");
1596 QTest::addColumn<QString>("expectedRelatedToUid");
1597
1598 Akonadi::Item item1;
1599 KCalCore::Todo::Ptr todo1(new KCalCore::Todo);
1600 item1.setPayload<KCalCore::Todo::Ptr>(todo1);
1601
1602 Domain::Task::Ptr parent(new Domain::Task);
1603 parent->setProperty("todoUid", "1");
1604
1605 QTest::newRow("nominal case") << item1 << parent << "1";
1606
1607 Akonadi::Item item2;
1608 QTest::newRow("update item without payload") << item2 << parent << QString();
1609
1610 Domain::Task::Ptr parent2(new Domain::Task);
1611 QTest::newRow("update item with a empty parent uid") << item1 << parent2 << QString();
1612 }
1613
shouldUpdateItemParent()1614 void shouldUpdateItemParent()
1615 {
1616 // GIVEN
1617 QFETCH(Akonadi::Item, item);
1618 QFETCH(Domain::Task::Ptr, parent);
1619 QFETCH(QString, expectedRelatedToUid);
1620
1621 // WHEN
1622 Akonadi::Serializer serializer;
1623 serializer.updateItemParent(item, parent);
1624
1625 // THEN
1626 if (item.hasPayload<KCalCore::Todo::Ptr>()) {
1627 auto todo = item.payload<KCalCore::Todo::Ptr>();
1628 QString relatedUid = todo->relatedTo();
1629 QCOMPARE(relatedUid, expectedRelatedToUid);
1630 }
1631 }
1632
shouldUpdateItemProject_data()1633 void shouldUpdateItemProject_data()
1634 {
1635 QTest::addColumn<Akonadi::Item>("item");
1636 QTest::addColumn<Domain::Project::Ptr>("parent");
1637 QTest::addColumn<QString>("expectedRelatedToUid");
1638
1639 Akonadi::Item todoItem;
1640 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1641 todoItem.setPayload<KCalCore::Todo::Ptr>(todo);
1642
1643 auto parent = Domain::Project::Ptr::create();
1644 parent->setProperty("todoUid", "1");
1645
1646 QTest::newRow("nominal todo case") << todoItem << parent << "1";
1647
1648 auto invalidParent = Domain::Project::Ptr::create();
1649 QTest::newRow("update todo item with a empty parent uid") << todoItem << invalidParent << QString();
1650
1651 Akonadi::Item invalidItem;
1652 QTest::newRow("update item without payload") << invalidItem << parent << QString();
1653 }
1654
shouldUpdateItemProject()1655 void shouldUpdateItemProject()
1656 {
1657 // GIVEN
1658 QFETCH(Akonadi::Item, item);
1659 QFETCH(Domain::Project::Ptr, parent);
1660 QFETCH(QString, expectedRelatedToUid);
1661
1662 // WHEN
1663 Akonadi::Serializer serializer;
1664 serializer.updateItemProject(item, parent);
1665
1666 // THEN
1667 if (item.hasPayload<KCalCore::Todo::Ptr>()) {
1668 auto todo = item.payload<KCalCore::Todo::Ptr>();
1669 const QString relatedUid = todo->relatedTo();
1670 QCOMPARE(relatedUid, expectedRelatedToUid);
1671 }
1672 }
1673
shouldFilterChildrenItem_data()1674 void shouldFilterChildrenItem_data()
1675 {
1676 QTest::addColumn<Akonadi::Item>("item");
1677 QTest::addColumn<Akonadi::Item::List>("items");
1678 QTest::addColumn<int>("size");
1679
1680 Akonadi::Item item(12);
1681 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1682 todo->setUid(QStringLiteral("1"));
1683 item.setPayload<KCalCore::Todo::Ptr>(todo);
1684 Akonadi::Item::List items;
1685
1686 QTest::newRow("empty list") << item << items << 0;
1687
1688 Akonadi::Item item2(13);
1689 KCalCore::Todo::Ptr todo2(new KCalCore::Todo);
1690 item2.setPayload<KCalCore::Todo::Ptr>(todo2);
1691 Akonadi::Item::List items2;
1692 items2 << item2;
1693
1694 QTest::newRow("list without child") << item << items2 << 0;
1695
1696 Akonadi::Item item3(14);
1697 KCalCore::Todo::Ptr todo3(new KCalCore::Todo);
1698 todo3->setUid(QStringLiteral("3"));
1699 todo3->setRelatedTo(QStringLiteral("1"));
1700 item3.setPayload<KCalCore::Todo::Ptr>(todo3);
1701 Akonadi::Item::List items3;
1702 items3 << item2 << item3;
1703
1704 QTest::newRow("list with child") << item << items3 << 1;
1705
1706 Akonadi::Item item4(15);
1707 KCalCore::Todo::Ptr todo4(new KCalCore::Todo);
1708 todo4->setRelatedTo(QStringLiteral("3"));
1709 item4.setPayload<KCalCore::Todo::Ptr>(todo4);
1710 Akonadi::Item::List items4;
1711 items4 << item2 << item3 << item4;
1712
1713 QTest::newRow("list with child with a child") << item << items4 << 2;
1714
1715 Akonadi::Item::List items5;
1716 items5 << item << item2 << item3 << item4;
1717 QTest::newRow("list with filter in list") << item << items5 << 2;
1718 }
1719
shouldFilterChildrenItem()1720 void shouldFilterChildrenItem()
1721 {
1722 // GIVEN
1723 QFETCH(Akonadi::Item, item);
1724 QFETCH(Akonadi::Item::List, items);
1725 QFETCH(int, size);
1726
1727 // WHEN
1728 Akonadi::Serializer serializer;
1729 Akonadi::Item::List list = serializer.filterDescendantItems(items, item);
1730
1731 // THEN
1732 QCOMPARE(list.size(), size);
1733 }
1734
shouldRemoveItemParent_data()1735 void shouldRemoveItemParent_data()
1736 {
1737 QTest::addColumn<Akonadi::Item>("item");
1738
1739 Akonadi::Item item(15);
1740 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1741 todo->setRelatedTo(QStringLiteral("3"));
1742 item.setPayload<KCalCore::Todo::Ptr>(todo);
1743
1744 QTest::newRow("nominal case") << item;
1745
1746 Akonadi::Item item2(16);
1747 QTest::newRow("parent invalid") << item2;
1748 }
1749
shouldRemoveItemParent()1750 void shouldRemoveItemParent()
1751 {
1752 // GIVEN
1753 QFETCH(Akonadi::Item, item);
1754
1755 // WHEN
1756 Akonadi::Serializer serializer;
1757 serializer.removeItemParent(item);
1758
1759 // THEN
1760 if (item.hasPayload<KCalCore::Todo::Ptr>())
1761 QCOMPARE(item.payload<KCalCore::Todo::Ptr>()->relatedTo(), QString());
1762 }
1763
shouldPromoteItemToProject_data()1764 void shouldPromoteItemToProject_data()
1765 {
1766 QTest::addColumn<Akonadi::Item>("item");
1767
1768 auto item = Akonadi::Item(15);
1769 auto todo = KCalCore::Todo::Ptr::create();
1770 todo->setRelatedTo(QStringLiteral("3"));
1771 item.setPayload(todo);
1772
1773 QTest::newRow("nominal case") << item;
1774 QTest::newRow("invalid item") << Akonadi::Item(16);
1775 }
1776
shouldPromoteItemToProject()1777 void shouldPromoteItemToProject()
1778 {
1779 // GIVEN
1780 QFETCH(Akonadi::Item, item);
1781
1782 // WHEN
1783 Akonadi::Serializer serializer;
1784 serializer.promoteItemToProject(item);
1785
1786 // THEN
1787 if (item.hasPayload<KCalCore::Todo::Ptr>()) {
1788 auto todo = item.payload<KCalCore::Todo::Ptr>();
1789 QCOMPARE(todo->relatedTo(), QString());
1790 QVERIFY(!todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject()).isEmpty());
1791 }
1792 }
1793
shouldClearItem_data()1794 void shouldClearItem_data()
1795 {
1796 QTest::addColumn<Akonadi::Item*>("item");
1797
1798 Akonadi::Item *itemWithContexts = new Akonadi::Item(15);
1799 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1800 // we can cheat and not really create contexts...
1801 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "one,two");
1802 itemWithContexts->setPayload<KCalCore::Todo::Ptr>(todo);
1803 QTest::newRow("with_contexts") << itemWithContexts;
1804
1805 Akonadi::Item *itemWithNoContext = new Akonadi::Item(15);
1806 itemWithNoContext->setPayload<KCalCore::Todo::Ptr>(todo);
1807 QTest::newRow("no_context") << itemWithNoContext;
1808 }
1809
shouldClearItem()1810 void shouldClearItem()
1811 {
1812 // GIVEN
1813 QFETCH(Akonadi::Item*, item);
1814
1815 // WHEN
1816 Akonadi::Serializer serializer;
1817 serializer.clearItem(item);
1818
1819 // THEN
1820 auto todo = item->payload<KCalCore::Todo::Ptr>();
1821 QVERIFY(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()).isEmpty());
1822 delete item;
1823 }
1824
shouldCreateContextFromItem_data()1825 void shouldCreateContextFromItem_data()
1826 {
1827 QTest::addColumn<QString>("name");
1828
1829 QTest::newRow("nominal case") << "Context42";
1830 QTest::newRow("empty name case") << "";
1831 }
1832
shouldCreateContextFromItem()1833 void shouldCreateContextFromItem()
1834 {
1835 // GIVEN
1836
1837 // Data...
1838 QFETCH(QString, name);
1839
1840 // ... stored in a todo...
1841 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1842 todo->setSummary(name);
1843 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext(), QStringLiteral("1"));
1844 QVERIFY(!todo->uid().isEmpty());
1845
1846 // ... as payload of an item
1847 Akonadi::Item item(42);
1848 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1849 item.setPayload<KCalCore::Todo::Ptr>(todo);
1850
1851 // which has a parent collection
1852 Akonadi::Collection collection(43);
1853 item.setParentCollection(collection);
1854
1855 // WHEN
1856 Akonadi::Serializer serializer;
1857 Domain::Context::Ptr context = serializer.createContextFromItem(item);
1858
1859 // THEN
1860 QCOMPARE(context->name(), name);
1861 QCOMPARE(context->property("todoUid").toString(), todo->uid());
1862 QCOMPARE(context->property("itemId").toLongLong(), item.id());
1863 QCOMPARE(context->property("parentCollectionId").toLongLong(), collection.id());
1864 }
1865
shouldNotCreateContextFromWrongItemType_data()1866 void shouldNotCreateContextFromWrongItemType_data()
1867 {
1868 QTest::addColumn<bool>("isProject");
1869
1870 QTest::newRow("project") << true;
1871 QTest::newRow("task") << false;
1872 }
1873
shouldNotCreateContextFromWrongItemType()1874 void shouldNotCreateContextFromWrongItemType()
1875 {
1876 // GIVEN
1877 QFETCH(bool, isProject);
1878
1879 // A project todo
1880 KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo);
1881 originalTodo->setSummary("summary");
1882 if (isProject)
1883 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1884
1885 // ... as payload of an item...
1886 Akonadi::Item originalItem;
1887 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1888 originalItem.setPayload<KCalCore::Todo::Ptr>(originalTodo);
1889
1890 // WHEN
1891 Akonadi::Serializer serializer;
1892 Domain::Context::Ptr context = serializer.createContextFromItem(originalItem);
1893
1894 // THEN
1895 QVERIFY(!context);
1896 }
1897
shouldUpdateContextFromItem_data()1898 void shouldUpdateContextFromItem_data()
1899 {
1900 shouldCreateContextFromItem_data();
1901 }
1902
shouldUpdateContextFromItem()1903 void shouldUpdateContextFromItem()
1904 {
1905 // GIVEN
1906
1907 // Data...
1908 QFETCH(QString, name);
1909
1910 // ... stored in a todo...
1911 KCalCore::Todo::Ptr todo(new KCalCore::Todo);
1912 todo->setSummary(name);
1913 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext(), QStringLiteral("1"));
1914 QVERIFY(!todo->uid().isEmpty());
1915
1916 // ... as payload of an item
1917 Akonadi::Item item(42);
1918 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1919 item.setPayload<KCalCore::Todo::Ptr>(todo);
1920
1921 // WHEN
1922 Akonadi::Serializer serializer;
1923 Domain::Context::Ptr context(new Domain::Context);
1924
1925 serializer.updateContextFromItem(context, item);
1926
1927 // THEN
1928 QCOMPARE(context->name(), name);
1929 QCOMPARE(context->property("todoUid").toString(), todo->uid());
1930 QCOMPARE(context->property("itemId").toLongLong(), item.id());
1931 }
1932
shouldNotUpdateContextFromWrongItemType_data()1933 void shouldNotUpdateContextFromWrongItemType_data()
1934 {
1935 QTest::addColumn<bool>("isProject");
1936
1937 QTest::newRow("project") << true;
1938 QTest::newRow("task") << false;
1939 }
1940
shouldNotUpdateContextFromWrongItemType()1941 void shouldNotUpdateContextFromWrongItemType()
1942 {
1943 // GIVEN
1944 QFETCH(bool, isProject);
1945
1946 // A context
1947 auto context = Domain::Context::Ptr::create();
1948 context->setName("summary");
1949 context->setProperty("todoUid", qint64(43));
1950
1951 KCalCore::Todo::Ptr wrongTodo(new KCalCore::Todo);
1952 wrongTodo->setSummary("wrongSummary");
1953 if (isProject)
1954 wrongTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1"));
1955
1956 Akonadi::Item wrongItem;
1957 wrongItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo"));
1958 wrongItem.setPayload<KCalCore::Todo::Ptr>(wrongTodo);
1959
1960 // WHEN
1961 Akonadi::Serializer serializer;
1962 serializer.updateContextFromItem(context, wrongItem);
1963
1964 // THEN
1965 QCOMPARE(context->name(), "summary");
1966 QCOMPARE(context->property("todoUid").toLongLong(), qint64(43));
1967 }
1968
shouldVerifyIfAnItemIsAContextChild_data()1969 void shouldVerifyIfAnItemIsAContextChild_data()
1970 {
1971 QTest::addColumn<Domain::Context::Ptr>("context");
1972 QTest::addColumn<Akonadi::Item>("item");
1973 QTest::addColumn<bool>("isChild");
1974
1975 // Create a context
1976 auto context = Domain::Context::Ptr::create();
1977 const QString contextUid = QStringLiteral("abc-123");
1978 context->setProperty("todoUid", contextUid);
1979
1980 Akonadi::Item unrelatedItem;
1981 QTest::newRow("Unrelated item") << context << unrelatedItem << false;
1982
1983 Akonadi::Item relatedItem;
1984 auto todo = KCalCore::Todo::Ptr::create();
1985 todo->setSummary("summary");
1986 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextUid);
1987 relatedItem.setPayload<KCalCore::Todo::Ptr>(todo);
1988 QTest::newRow("Related item") << context << relatedItem << true;
1989
1990 auto invalidContext = Domain::Context::Ptr::create();
1991 QTest::newRow("Invalid context") << invalidContext << relatedItem << false;
1992
1993 Akonadi::Item invalidItem;
1994 QTest::newRow("Invalid Item") << context << invalidItem << false;
1995 }
1996
shouldVerifyIfAnItemIsAContextChild()1997 void shouldVerifyIfAnItemIsAContextChild()
1998 {
1999 // GIVEN
2000 QFETCH(Domain::Context::Ptr, context);
2001 QFETCH(Akonadi::Item, item);
2002 QFETCH(bool, isChild);
2003
2004 // WHEN
2005 Akonadi::Serializer serializer;
2006 bool value = serializer.isContextChild(context, item);
2007
2008 // THEN
2009 QCOMPARE(value, isChild);
2010 }
2011
shouldCreateItemFromContext_data()2012 void shouldCreateItemFromContext_data()
2013 {
2014 QTest::addColumn<QString>("name");
2015 QTest::addColumn<qint64>("itemId");
2016 QTest::addColumn<QString>("todoUid");
2017
2018 const QString nameInternet = QStringLiteral("Internet");
2019 const QString uid = QStringLiteral("uid-123");
2020
2021 QTest::newRow("nominal_case") << nameInternet << qint64(42) << uid;
2022 QTest::newRow("no_item_id") << nameInternet<< qint64(-1) << uid;
2023 QTest::newRow("null_uid") << nameInternet << qint64(42) << QString();
2024 QTest::newRow("no_name") << QString() << qint64(42) << uid;
2025 }
2026
shouldCreateItemFromContext()2027 void shouldCreateItemFromContext()
2028 {
2029 // GIVEN
2030 QFETCH(QString, name);
2031 QFETCH(qint64, itemId);
2032 QFETCH(QString, todoUid);
2033
2034 // WHEN
2035 auto context = Domain::Context::Ptr::create();
2036 context->setProperty("todoUid", todoUid);
2037 if (itemId > 0)
2038 context->setProperty("itemId", itemId);
2039
2040 context->setName(name);
2041
2042 Akonadi::Serializer serializer;
2043 Akonadi::Item item = serializer.createItemFromContext(context);
2044 auto todo = item.payload<KCalCore::Todo::Ptr>();
2045
2046 // THEN
2047 QCOMPARE(todo->summary(), name);
2048
2049 if (!todoUid.isEmpty()) {
2050 QCOMPARE(todo->uid(), todoUid);
2051 }
2052 QCOMPARE(item.id(), itemId);
2053 }
2054
shouldTestIfItemRepresentsContext_data()2055 void shouldTestIfItemRepresentsContext_data()
2056 {
2057 QTest::addColumn<QString>("contextUid");
2058 QTest::addColumn<QString>("todoUid");
2059 QTest::addColumn<bool>("expectedResult");
2060
2061 QTest::newRow("yes") << "context-123" << "context-123" << true;
2062 QTest::newRow("no") << "context-123" << "another-context" << false;
2063 }
2064
shouldAddContextToTask_data()2065 void shouldAddContextToTask_data()
2066 {
2067 QTest::addColumn<Domain::Context::Ptr>("context");
2068 QTest::addColumn<Akonadi::Item>("item");
2069 QTest::addColumn<QString>("expectedContextList");
2070
2071 // Create a context
2072 auto context = Domain::Context::Ptr::create();
2073 const QString contextUid = QStringLiteral("abc-123");
2074 context->setProperty("todoUid", contextUid);
2075
2076 Akonadi::Item item;
2077 auto todo = KCalCore::Todo::Ptr::create();
2078 todo->setSummary("summary");
2079 item.setPayload<KCalCore::Todo::Ptr>(todo);
2080 QTest::newRow("item_with_no_context") << context << item << contextUid;
2081
2082 Akonadi::Item item2;
2083 auto todo2 = KCalCore::Todo::Ptr::create();
2084 todo2->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "another");
2085 item2.setPayload<KCalCore::Todo::Ptr>(todo2);
2086 const QString bothContexts = QStringLiteral("another,") + contextUid;
2087 QTest::newRow("item_with_another_context") << context << item2 << bothContexts;
2088
2089 Akonadi::Item item3;
2090 auto todo3 = KCalCore::Todo::Ptr::create();
2091 todo3->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), bothContexts);
2092 item3.setPayload<KCalCore::Todo::Ptr>(todo3);
2093 QTest::newRow("item_with_this_context_already") << context << item3 << bothContexts;
2094 }
2095
shouldAddContextToTask()2096 void shouldAddContextToTask()
2097 {
2098 // GIVEN
2099 QFETCH(Domain::Context::Ptr, context);
2100 QFETCH(Akonadi::Item, item);
2101 QFETCH(QString, expectedContextList);
2102
2103 // WHEN
2104 Akonadi::Serializer serializer;
2105 serializer.addContextToTask(context, item);
2106
2107 // THEN
2108 KCalCore::Todo::Ptr todo = item.payload<KCalCore::Todo::Ptr>();
2109 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), expectedContextList);
2110 }
2111
shouldRemoveContextFromTask_data()2112 void shouldRemoveContextFromTask_data()
2113 {
2114 QTest::addColumn<Domain::Context::Ptr>("context");
2115 QTest::addColumn<Akonadi::Item>("item");
2116 QTest::addColumn<QString>("expectedContextList");
2117
2118 auto context = Domain::Context::Ptr::create();
2119 const QString contextUid = QStringLiteral("abc-123");
2120 context->setProperty("todoUid", contextUid);
2121
2122 Akonadi::Item item;
2123 auto todo = KCalCore::Todo::Ptr::create();
2124 todo->setSummary("summary");
2125 item.setPayload<KCalCore::Todo::Ptr>(todo);
2126 QTest::newRow("item_with_no_context") << context << item << QString();
2127
2128 Akonadi::Item item2;
2129 auto todo2 = KCalCore::Todo::Ptr::create();
2130 todo2->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "another");
2131 item2.setPayload<KCalCore::Todo::Ptr>(todo2);
2132 QTest::newRow("item_with_another_context") << context << item2 << QString("another");
2133
2134 Akonadi::Item item3;
2135 auto todo3 = KCalCore::Todo::Ptr::create();
2136 todo3->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextUid);
2137 item3.setPayload<KCalCore::Todo::Ptr>(todo3);
2138 QTest::newRow("item_with_this_context_already") << context << item3 << QString();
2139
2140 Akonadi::Item item4;
2141 auto todo4 = KCalCore::Todo::Ptr::create();
2142 const QString bothContexts = QStringLiteral("another,") + contextUid;
2143 todo4->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), bothContexts);
2144 item4.setPayload<KCalCore::Todo::Ptr>(todo4);
2145 QTest::newRow("item_with_two_contexts") << context << item4 << QString("another");
2146 }
2147
shouldRemoveContextFromTask()2148 void shouldRemoveContextFromTask()
2149 {
2150 // GIVEN
2151 QFETCH(Domain::Context::Ptr, context);
2152 QFETCH(Akonadi::Item, item);
2153 QFETCH(QString, expectedContextList);
2154
2155 // WHEN
2156 Akonadi::Serializer serializer;
2157 serializer.removeContextFromTask(context, item);
2158
2159 // THEN
2160 KCalCore::Todo::Ptr todo = item.payload<KCalCore::Todo::Ptr>();
2161 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), expectedContextList);
2162 }
2163
2164 // Investigation into how to differentiate all-day events from events with time,
2165 // using QDateTime only. Doesn't seem to be possible.
noWayToHaveQDateTimeWithoutTime()2166 void noWayToHaveQDateTimeWithoutTime()
2167 {
2168 // GIVEN a QDateTime without time information
2169 QDateTime dateOnly(QDate(2016, 6, 12), QTime(-1, -1, -1));
2170 // THEN we can't detect that there was no time information, i.e. all day event
2171 QVERIFY(dateOnly.time().isValid()); // I wish this was "!"
2172 QVERIFY(!dateOnly.time().isNull()); // got converted to midnight localtime by QDateTime
2173 // This doesn't help, QDateTime converts "null time" to midnight.
2174 dateOnly.setTime(QTime());
2175 QVERIFY(dateOnly.time().isValid()); // same as above
2176 QVERIFY(!dateOnly.time().isNull()); // same as above
2177
2178 // GIVEN a QDateTime at midnight
2179 QDateTime atMidnight(QDate(2016, 6, 12), QTime(0, 0, 0));
2180 // THEN we can detect that a time information was present
2181 QVERIFY(atMidnight.time().isValid());
2182 QVERIFY(!atMidnight.time().isNull());
2183
2184 #if 0
2185 // GIVEN a KDateTime without time information
2186 KDateTime kdOnly(QDate(2016, 6, 12));
2187 // THEN we can detect that there was no time information, i.e. all day event
2188 QVERIFY(kdOnly.isDateOnly());
2189 #endif
2190 }
2191 };
2192
2193 ZANSHIN_TEST_MAIN(AkonadiSerializerTest)
2194
2195 #include "akonadiserializertest.moc"
2196