File indexing completed on 2025-01-05 04:59:54
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org> 0003 SPDX-FileCopyrightText: 2014 Rémi Benoit <r3m1.benoit@gmail.com> 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 0008 #include <testlib/qtest_zanshin.h> 0009 0010 #include "akonadi/akonadiserializer.h" 0011 #include "akonadi/akonadiapplicationselectedattribute.h" 0012 #include "akonadi/akonaditimestampattribute.h" 0013 0014 #include <Akonadi/Collection> 0015 #include <Akonadi/EntityDisplayAttribute> 0016 #include <Akonadi/Item> 0017 #include <KCalendarCore/Todo> 0018 #if __has_include(<kcalcore_version.h>) 0019 #include <kcalcore_version.h> 0020 #else 0021 #include <kcalendarcore_version.h> 0022 #endif 0023 0024 Q_DECLARE_METATYPE(Akonadi::Item*) 0025 0026 using Akonadi::Serializer; 0027 0028 static void setTodoDates(KCalendarCore::Todo::Ptr todo, const QDate &start, const QDate &due) { 0029 todo->setDtStart(start.startOfDay()); 0030 todo->setDtDue(due.startOfDay()); 0031 } 0032 0033 class AkonadiSerializerTest : public QObject 0034 { 0035 Q_OBJECT 0036 private slots: 0037 void shouldKnowWhenAnObjectRepresentsACollection() 0038 { 0039 // GIVEN 0040 Akonadi::Serializer serializer; 0041 auto object = Akonadi::Serializer::QObjectPtr::create(); 0042 Akonadi::Collection collection(42); 0043 0044 // WHEN 0045 // Nothing yet 0046 0047 // THEN 0048 QVERIFY(!serializer.representsCollection(object, collection)); 0049 0050 // WHEN 0051 object->setProperty("collectionId", 42); 0052 0053 // THEN 0054 QVERIFY(serializer.representsCollection(object, collection)); 0055 0056 // WHEN 0057 object->setProperty("collectionId", 43); 0058 0059 // THEN 0060 QVERIFY(!serializer.representsCollection(object, collection)); 0061 } 0062 0063 void shouldKnowWhenAnObjectRepresentsAnItem() 0064 { 0065 // GIVEN 0066 Akonadi::Serializer serializer; 0067 auto object = Akonadi::Serializer::QObjectPtr::create(); 0068 Akonadi::Item item(42); 0069 0070 // WHEN 0071 // Nothing yet 0072 0073 // THEN 0074 QVERIFY(!serializer.representsItem(object, item)); 0075 0076 // WHEN 0077 object->setProperty("itemId", 42); 0078 0079 // THEN 0080 QVERIFY(serializer.representsItem(object, item)); 0081 0082 // WHEN 0083 object->setProperty("itemId", 43); 0084 0085 // THEN 0086 QVERIFY(!serializer.representsItem(object, item)); 0087 } 0088 0089 void shouldKnowTaskItemUid_data() 0090 { 0091 QTest::addColumn<Akonadi::Item>("item"); 0092 QTest::addColumn<QString>("expectedUid"); 0093 0094 Akonadi::Item item1; 0095 KCalendarCore::Todo::Ptr todo1(new KCalendarCore::Todo); 0096 todo1->setUid(QString()); 0097 item1.setPayload<KCalendarCore::Todo::Ptr>(todo1); 0098 0099 Akonadi::Item item2; 0100 KCalendarCore::Todo::Ptr todo2(new KCalendarCore::Todo); 0101 todo2->setUid(QStringLiteral("1")); 0102 item2.setPayload<KCalendarCore::Todo::Ptr>(todo2); 0103 0104 QTest::newRow("task without uid") << item1 << QString(); 0105 QTest::newRow("task with uid") << item2 << "1"; 0106 } 0107 0108 void shouldKnowTaskItemUid() 0109 { 0110 // GIVEN 0111 QFETCH(Akonadi::Item, item); 0112 QFETCH(QString, expectedUid); 0113 0114 // WHEN 0115 Akonadi::Serializer serializer; 0116 QString uid = serializer.itemUid(item); 0117 0118 // THEN 0119 QCOMPARE(uid, expectedUid); 0120 } 0121 0122 void shouldCreateDataSourceFromCollection_data() 0123 { 0124 QTest::addColumn<QString>("name"); 0125 QTest::addColumn<QString>("iconName"); 0126 QTest::addColumn<QStringList>("mimeTypes"); 0127 QTest::addColumn<bool>("hasSelectedAttribute"); 0128 QTest::addColumn<bool>("isSelected"); 0129 0130 const auto noteMimeTypes = QStringList() << QStringLiteral("text/x-vnd.akonadi.note"); 0131 const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); 0132 const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar"); 0133 const auto allMimeTypes = noteMimeTypes + taskMimeTypes + bogusMimeTypes; 0134 0135 QTest::newRow("nominal case") << "name" << "icon" << allMimeTypes << true << false; 0136 0137 QTest::newRow("only notes") << "name" << "icon" << noteMimeTypes << true << false; 0138 QTest::newRow("only tasks") << "name" << "icon" << taskMimeTypes << true << false; 0139 QTest::newRow("only bogus") << "name" << "icon" << bogusMimeTypes << true << false; 0140 0141 QTest::newRow("no selected attribute") << "name" << "icon" << allMimeTypes << false << false; 0142 QTest::newRow("selected attribute (false)") << "name" << "icon" << allMimeTypes << true << false; 0143 QTest::newRow("selected attribute (true)") << "name" << "icon" << allMimeTypes << true << true; 0144 0145 QTest::newRow("empty case") << QString() << QString() << QStringList() << false << false; 0146 } 0147 0148 void shouldCreateDataSourceFromCollection() 0149 { 0150 // GIVEN 0151 0152 // Data... 0153 QFETCH(QString, name); 0154 QFETCH(QString, iconName); 0155 QFETCH(QStringList, mimeTypes); 0156 QFETCH(bool, hasSelectedAttribute); 0157 QFETCH(bool, isSelected); 0158 0159 Domain::DataSource::ContentTypes expectedContentTypes; 0160 if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) { 0161 expectedContentTypes |= Domain::DataSource::Tasks; 0162 } 0163 0164 // ... stored in a collection 0165 Akonadi::Collection collection(42); 0166 collection.setContentMimeTypes(mimeTypes); 0167 collection.setName(name); 0168 auto displayAttribute = new Akonadi::EntityDisplayAttribute; 0169 displayAttribute->setIconName(iconName); 0170 collection.addAttribute(displayAttribute); 0171 if (hasSelectedAttribute) { 0172 auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute; 0173 selectedAttribute->setSelected(isSelected); 0174 collection.addAttribute(selectedAttribute); 0175 } 0176 0177 // WHEN 0178 Akonadi::Serializer serializer; 0179 auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); 0180 0181 // THEN 0182 QCOMPARE(dataSource->name(), name); 0183 QCOMPARE(dataSource->iconName(), iconName); 0184 QCOMPARE(dataSource->contentTypes(), expectedContentTypes); 0185 QCOMPARE(dataSource->isSelected(), !hasSelectedAttribute || isSelected); 0186 QCOMPARE(dataSource->property("collectionId").value<Akonadi::Collection::Id>(), collection.id()); 0187 } 0188 0189 void shouldCreateNullDataSourceFromInvalidCollection() 0190 { 0191 // GIVEN 0192 Akonadi::Collection collection; 0193 0194 // WHEN 0195 Akonadi::Serializer serializer; 0196 auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); 0197 0198 // THEN 0199 QVERIFY(dataSource.isNull()); 0200 } 0201 0202 void shouldUpdateDataSourceFromCollection_data() 0203 { 0204 QTest::addColumn<QString>("updatedName"); 0205 0206 QTest::newRow("no change") << "name"; 0207 QTest::newRow("changed") << "new name"; 0208 } 0209 0210 void shouldUpdateDataSourceFromCollection() 0211 { 0212 // GIVEN 0213 0214 // A collection... 0215 Akonadi::Collection originalCollection(42); 0216 originalCollection.setName(QStringLiteral("name")); 0217 0218 // ... deserialized as a data source 0219 Akonadi::Serializer serializer; 0220 auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName); 0221 0222 // WHEN 0223 0224 // Data... 0225 QFETCH(QString, updatedName); 0226 0227 // ... in a new collection 0228 Akonadi::Collection updatedCollection(42); 0229 updatedCollection.setName(updatedName); 0230 0231 serializer.updateDataSourceFromCollection(dataSource, updatedCollection, Akonadi::SerializerInterface::BaseName); 0232 0233 // THEN 0234 QCOMPARE(dataSource->name(), updatedName); 0235 } 0236 0237 void shouldNotUpdateDataSourceFromInvalidCollection() 0238 { 0239 // GIVEN 0240 0241 // Data... 0242 const QString name = QStringLiteral("name"); 0243 0244 // ... stored in a collection... 0245 Akonadi::Collection originalCollection(42); 0246 originalCollection.setName(name); 0247 0248 // ... deserialized as a data source 0249 Akonadi::Serializer serializer; 0250 auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName); 0251 0252 // WHEN 0253 Akonadi::Collection invalidCollection; 0254 invalidCollection.setName(QStringLiteral("foo")); 0255 serializer.updateDataSourceFromCollection(dataSource, invalidCollection, Akonadi::SerializerInterface::BaseName); 0256 0257 // THEN 0258 QCOMPARE(dataSource->name(), name); 0259 } 0260 0261 void shouldNameDataSourceFromCollectionPathIfRequested() 0262 { 0263 // GIVEN 0264 0265 // Data... 0266 const QString name = QStringLiteral("name"); 0267 const QString parentName = QStringLiteral("parent"); 0268 0269 // ... stored in a collection with a parent 0270 Akonadi::Collection collection(42); 0271 collection.setName(name); 0272 Akonadi::Collection parentCollection(41); 0273 parentCollection.setName(QStringLiteral("Foo")); 0274 auto attribute = new Akonadi::EntityDisplayAttribute; 0275 attribute->setDisplayName(parentName); 0276 parentCollection.addAttribute(attribute); 0277 collection.setParentCollection(parentCollection); 0278 0279 // WHEN 0280 Akonadi::Serializer serializer; 0281 auto dataSource1 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath); 0282 auto dataSource2 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); 0283 0284 // Give it another try with the root 0285 parentCollection.setParentCollection(Akonadi::Collection::root()); 0286 collection.setParentCollection(parentCollection); 0287 auto dataSource3 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath); 0288 auto dataSource4 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); 0289 0290 // THEN 0291 QCOMPARE(dataSource1->name(), QString(parentName + " » " + name)); 0292 QCOMPARE(dataSource2->name(), name); 0293 QCOMPARE(dataSource3->name(), QString(parentName + " » " + name)); 0294 QCOMPARE(dataSource4->name(), name); 0295 } 0296 0297 void shouldCreateCollectionFromDataSource_data() 0298 { 0299 QTest::addColumn<QString>("name"); 0300 QTest::addColumn<QString>("iconName"); 0301 QTest::addColumn<Domain::DataSource::ContentTypes>("contentTypes"); 0302 QTest::addColumn<bool>("isSelected"); 0303 0304 const auto noType = Domain::DataSource::ContentTypes(Domain::DataSource::NoContent); 0305 const auto taskType = Domain::DataSource::ContentTypes(Domain::DataSource::Tasks); 0306 0307 QTest::newRow("only tasks") << "name" << "icon-name" << taskType << true; 0308 QTest::newRow("only nothing ;)") << "name" << "icon-name" << noType << true; 0309 0310 QTest::newRow("not selected") << "name" << "icon-name" << taskType << false; 0311 QTest::newRow("selected") << "name" << "icon-name" << taskType << true; 0312 0313 QTest::newRow("empty case") << QString() << QString() << noType << true; 0314 } 0315 0316 void shouldCreateCollectionFromDataSource() 0317 { 0318 // GIVEN 0319 const auto timestamp = QDateTime::currentMSecsSinceEpoch(); 0320 0321 // Data... 0322 QFETCH(QString, name); 0323 QFETCH(QString, iconName); 0324 QFETCH(Domain::DataSource::ContentTypes, contentTypes); 0325 QFETCH(bool, isSelected); 0326 0327 QStringList mimeTypes; 0328 if (contentTypes & Domain::DataSource::Tasks) 0329 mimeTypes << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); 0330 0331 0332 // ... stored in a data source 0333 auto source = Domain::DataSource::Ptr::create(); 0334 source->setName(name); 0335 source->setIconName(iconName); 0336 source->setContentTypes(contentTypes); 0337 source->setSelected(isSelected); 0338 source->setProperty("collectionId", 42); 0339 0340 // WHEN 0341 Akonadi::Serializer serializer; 0342 auto collection = serializer.createCollectionFromDataSource(source); 0343 0344 // THEN 0345 QCOMPARE(collection.id(), source->property("collectionId").value<Akonadi::Collection::Id>()); 0346 QVERIFY(collection.hasAttribute<Akonadi::ApplicationSelectedAttribute>()); 0347 QCOMPARE(collection.attribute<Akonadi::ApplicationSelectedAttribute>()->isSelected(), isSelected); 0348 QVERIFY(collection.hasAttribute<Akonadi::TimestampAttribute>()); 0349 QVERIFY(collection.attribute<Akonadi::TimestampAttribute>()->timestamp() >= timestamp); 0350 } 0351 0352 void shouldVerifyIfCollectionIsSelected_data() 0353 { 0354 QTest::addColumn<QStringList>("mimeTypes"); 0355 QTest::addColumn<bool>("hasSelectedAttribute"); 0356 QTest::addColumn<bool>("isSelected"); 0357 QTest::addColumn<bool>("expectedSelected"); 0358 0359 const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); 0360 const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar"); 0361 const auto allMimeTypes = taskMimeTypes + bogusMimeTypes; 0362 0363 QTest::newRow("nominal case") << allMimeTypes << true << false << false; 0364 0365 QTest::newRow("only tasks") << taskMimeTypes << true << false << false; 0366 QTest::newRow("only bogus") << bogusMimeTypes << true << false << false; 0367 0368 QTest::newRow("selected, only tasks") << taskMimeTypes << true << true << true; 0369 QTest::newRow("selected, only bogus") << bogusMimeTypes << true << true << false; 0370 0371 QTest::newRow("no selected attribute") << allMimeTypes << false << false << true; 0372 QTest::newRow("selected attribute (false)") << allMimeTypes << true << false << false; 0373 QTest::newRow("selected attribute (true)") << allMimeTypes << true << true << true; 0374 0375 QTest::newRow("empty case") << QStringList() << false << false << false; 0376 } 0377 0378 void shouldVerifyIfCollectionIsSelected() 0379 { 0380 // GIVEN 0381 QFETCH(QStringList, mimeTypes); 0382 QFETCH(bool, hasSelectedAttribute); 0383 QFETCH(bool, isSelected); 0384 0385 Domain::DataSource::ContentTypes expectedContentTypes; 0386 if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) { 0387 expectedContentTypes |= Domain::DataSource::Tasks; 0388 } 0389 0390 // ... stored in a collection 0391 Akonadi::Collection collection(42); 0392 collection.setContentMimeTypes(mimeTypes); 0393 if (hasSelectedAttribute) { 0394 auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute; 0395 selectedAttribute->setSelected(isSelected); 0396 collection.addAttribute(selectedAttribute); 0397 } 0398 0399 // WHEN 0400 Akonadi::Serializer serializer; 0401 0402 // THEN 0403 QFETCH(bool, expectedSelected); 0404 QCOMPARE(serializer.isSelectedCollection(collection), expectedSelected); 0405 } 0406 0407 void shouldVerifyCollectionContents_data() 0408 { 0409 QTest::addColumn<QString>("mimeType"); 0410 QTest::addColumn<bool>("expectedTasks"); 0411 0412 QTest::newRow("task collection") << "application/x-vnd.akonadi.calendar.todo" << true; 0413 QTest::newRow("note collection") << "text/x-vnd.akonadi.note" << false; 0414 } 0415 0416 void shouldVerifyCollectionContents() 0417 { 0418 // GIVEN 0419 0420 // Data... 0421 QFETCH(QString, mimeType); 0422 0423 // ... stored in a collection 0424 Akonadi::Collection collection(42); 0425 collection.setContentMimeTypes(QStringList() << mimeType); 0426 0427 // WHEN 0428 Akonadi::Serializer serializer; 0429 QFETCH(bool, expectedTasks); 0430 0431 // THEN 0432 QCOMPARE(serializer.isTaskCollection(collection), expectedTasks); 0433 } 0434 0435 void shouldCreateTaskFromItem_data() 0436 { 0437 QTest::addColumn<QString>("summary"); 0438 QTest::addColumn<QString>("content"); 0439 QTest::addColumn<bool>("isDone"); 0440 QTest::addColumn<QDate>("doneDate"); 0441 QTest::addColumn<QDate>("startDate"); 0442 QTest::addColumn<QDate>("dueDate"); 0443 QTest::addColumn<QStringList>("contexts"); 0444 0445 QTest::newRow("nominal case") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList(); 0446 QTest::newRow("done case") << "summary" << "content" << true << QDate(2013, 11, 30) << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList(); 0447 QTest::newRow("done without doneDate case") << "summary" << "content" << true << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList(); 0448 QTest::newRow("empty case") << QString() << QString() << false << QDate() << QDate() << QDate() << QStringList(); 0449 QTest::newRow("one_context") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList({"mycontext"}); 0450 QTest::newRow("two_contexts") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << QStringList({"c1", "c2"}); 0451 } 0452 0453 void shouldCreateTaskFromItem() 0454 { 0455 // GIVEN 0456 0457 // Data... 0458 QFETCH(QString, summary); 0459 QFETCH(QString, content); 0460 QFETCH(bool, isDone); 0461 QFETCH(QDate, doneDate); 0462 QFETCH(QDate, startDate); 0463 QFETCH(QDate, dueDate); 0464 QFETCH(QStringList, contexts); 0465 0466 // ... stored in a todo... 0467 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 0468 todo->setSummary(summary); 0469 todo->setDescription(content); 0470 0471 if (isDone) 0472 todo->setCompleted(doneDate.startOfDay()); 0473 else 0474 todo->setCompleted(isDone); 0475 0476 setTodoDates(todo, startDate, dueDate); 0477 todo->setRelatedTo(QStringLiteral("my-uid")); 0478 0479 if (!contexts.isEmpty()) 0480 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contexts.join(',')); 0481 0482 // ... as payload of an item 0483 Akonadi::Item item; 0484 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0485 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 0486 0487 // which has a parent collection 0488 Akonadi::Collection collection(43); 0489 item.setParentCollection(collection); 0490 0491 // WHEN 0492 Akonadi::Serializer serializer; 0493 auto task = serializer.createTaskFromItem(item); 0494 0495 // THEN 0496 QVERIFY(!task.isNull()); 0497 QCOMPARE(task->title(), summary); 0498 QCOMPARE(task->text(), content); 0499 QCOMPARE(task->isDone(), isDone); 0500 QCOMPARE(task->doneDate(), doneDate); 0501 QCOMPARE(task->startDate(), startDate); 0502 QCOMPARE(task->dueDate(), dueDate); 0503 QCOMPARE(task->property("todoUid").toString(), todo->uid()); 0504 QCOMPARE(task->property("relatedUid").toString(), todo->relatedTo()); 0505 QCOMPARE(task->property("contextUids").toStringList(), contexts); 0506 QCOMPARE(task->property("itemId").toLongLong(), item.id()); 0507 QCOMPARE(task->property("parentCollectionId").toLongLong(), collection.id()); 0508 } 0509 0510 void shouldCreateNullTaskFromInvalidItem() 0511 { 0512 // GIVEN 0513 Akonadi::Item item; 0514 0515 // WHEN 0516 Akonadi::Serializer serializer; 0517 auto task = serializer.createTaskFromItem(item); 0518 0519 // THEN 0520 QVERIFY(task.isNull()); 0521 } 0522 0523 void shouldCreateNullTaskFromProjectItem() 0524 { 0525 // GIVEN 0526 0527 // A todo with the project flag 0528 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 0529 todo->setSummary(QStringLiteral("foo")); 0530 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 0531 0532 // ... as payload of an item 0533 Akonadi::Item item; 0534 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0535 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 0536 0537 // WHEN 0538 Akonadi::Serializer serializer; 0539 auto task = serializer.createTaskFromItem(item); 0540 0541 // THEN 0542 QVERIFY(task.isNull()); 0543 } 0544 0545 void shouldUpdateTaskFromItem_data() 0546 { 0547 QTest::addColumn<QString>("updatedSummary"); 0548 QTest::addColumn<QString>("updatedContent"); 0549 QTest::addColumn<bool>("updatedDone"); 0550 QTest::addColumn<QDate>("updatedDoneDate"); 0551 QTest::addColumn<QDate>("updatedStartDate"); 0552 QTest::addColumn<QDate>("updatedDueDate"); 0553 QTest::addColumn<QString>("updatedRelated"); 0554 QTest::addColumn<QString>("updatedContexts"); 0555 QTest::addColumn<bool>("updatedRecurs"); 0556 QTest::addColumn<QByteArrayList>("updatedAttachmentData"); 0557 QTest::addColumn<QStringList>("updatedAttachmentUris"); 0558 QTest::addColumn<QStringList>("updatedAttachmentLabels"); 0559 QTest::addColumn<QStringList>("updatedAttachmentMimeTypes"); 0560 QTest::addColumn<QStringList>("updatedAttachmentIconNames"); 0561 QTest::addColumn<bool>("updatedRunning"); 0562 0563 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; 0564 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; 0565 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; 0566 } 0567 0568 void shouldUpdateTaskFromItem() 0569 { 0570 // GIVEN 0571 0572 // A todo... 0573 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 0574 originalTodo->setSummary(QStringLiteral("summary")); 0575 originalTodo->setDescription(QStringLiteral("content")); 0576 originalTodo->setCompleted(false); 0577 setTodoDates(originalTodo, QDate(2013, 11, 24), QDate(2014, 03, 01)); 0578 0579 originalTodo->setRelatedTo(QStringLiteral("my-uid")); 0580 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), 0581 Serializer::customPropertyContextList(), 0582 QStringLiteral("context1,context2")); 0583 KCalendarCore::Attendee originalAttendee(QStringLiteral("John Doe"), 0584 QStringLiteral("j@d.com"), 0585 true, 0586 KCalendarCore::Attendee::Accepted); 0587 originalTodo->addAttendee(originalAttendee); 0588 0589 // ... as payload of an item... 0590 Akonadi::Item originalItem; 0591 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0592 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 0593 0594 // ... which has a parent collection... 0595 Akonadi::Collection originalCollection(43); 0596 originalItem.setParentCollection(originalCollection); 0597 0598 // ... deserialized as a task 0599 Akonadi::Serializer serializer; 0600 auto task = serializer.createTaskFromItem(originalItem); 0601 0602 // WHEN 0603 0604 // Data... 0605 QFETCH(QString, updatedSummary); 0606 QFETCH(QString, updatedContent); 0607 QFETCH(bool, updatedDone); 0608 QFETCH(QDate, updatedDoneDate); 0609 QFETCH(QDate, updatedStartDate); 0610 QFETCH(QDate, updatedDueDate); 0611 QFETCH(QString, updatedRelated); 0612 QFETCH(QString, updatedContexts); 0613 QFETCH(bool, updatedRecurs); 0614 QFETCH(QByteArrayList, updatedAttachmentData); 0615 QFETCH(QStringList, updatedAttachmentUris); 0616 QFETCH(QStringList, updatedAttachmentLabels); 0617 QFETCH(QStringList, updatedAttachmentMimeTypes); 0618 QFETCH(QStringList, updatedAttachmentIconNames); 0619 QFETCH(bool, updatedRunning); 0620 0621 // ... in a new todo... 0622 KCalendarCore::Todo::Ptr updatedTodo(new KCalendarCore::Todo); 0623 updatedTodo->setSummary(updatedSummary); 0624 updatedTodo->setDescription(updatedContent); 0625 0626 if (updatedDone) 0627 updatedTodo->setCompleted(updatedDoneDate.startOfDay()); 0628 else 0629 updatedTodo->setCompleted(updatedDone); 0630 0631 setTodoDates(updatedTodo, updatedStartDate, updatedDueDate); 0632 updatedTodo->setRelatedTo(updatedRelated); 0633 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(), 0634 Serializer::customPropertyContextList(), 0635 updatedContexts); 0636 0637 if (updatedRecurs) 0638 updatedTodo->recurrence()->setDaily(1); 0639 0640 for (int i = 0; i < updatedAttachmentData.size(); i++) { 0641 KCalendarCore::Attachment attachment(QByteArray{}); 0642 if (!updatedAttachmentData.at(i).isEmpty()) 0643 attachment.setDecodedData(updatedAttachmentData.at(i)); 0644 else 0645 attachment.setUri(updatedAttachmentUris.at(i)); 0646 attachment.setMimeType(updatedAttachmentMimeTypes.at(i)); 0647 attachment.setLabel(updatedAttachmentLabels.at(i)); 0648 updatedTodo->addAttachment(attachment); 0649 } 0650 0651 if (updatedRunning) { 0652 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning(), "1"); 0653 } else { 0654 updatedTodo->removeCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning()); 0655 } 0656 0657 // ... as payload of a new item 0658 Akonadi::Item updatedItem; 0659 updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0660 updatedItem.setPayload<KCalendarCore::Todo::Ptr>(updatedTodo); 0661 0662 // ... which has a new parent collection 0663 Akonadi::Collection updatedCollection(45); 0664 updatedItem.setParentCollection(updatedCollection); 0665 0666 serializer.updateTaskFromItem(task, updatedItem); 0667 0668 // THEN 0669 QCOMPARE(task->title(), updatedSummary); 0670 QCOMPARE(task->text(), updatedContent); 0671 QCOMPARE(task->isDone(), updatedDone); 0672 QCOMPARE(task->doneDate(), updatedDoneDate); 0673 QCOMPARE(task->startDate(), updatedStartDate); 0674 QCOMPARE(task->dueDate(), updatedDueDate); 0675 QCOMPARE(task->property("todoUid").toString(), updatedTodo->uid()); 0676 QCOMPARE(task->property("relatedUid").toString(), updatedTodo->relatedTo()); 0677 QCOMPARE(task->property("contextUids").toStringList(), updatedContexts.split(',')); 0678 QCOMPARE(task->property("itemId").toLongLong(), updatedItem.id()); 0679 QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id()); 0680 QCOMPARE(task->recurrence(), (updatedRecurs ? Domain::Task::RecursDaily : Domain::Task::NoRecurrence)); 0681 QCOMPARE(task->attachments().size(), updatedAttachmentData.size()); 0682 for (int i = 0; i < task->attachments().size(); i++) { 0683 const auto attachment = task->attachments().at(i); 0684 QCOMPARE(attachment.data(), updatedAttachmentData.at(i)); 0685 QCOMPARE(attachment.uri(), QUrl(updatedAttachmentUris.at(i))); 0686 QCOMPARE(attachment.label(), updatedAttachmentLabels.at(i)); 0687 QCOMPARE(attachment.mimeType(), updatedAttachmentMimeTypes.at(i)); 0688 QCOMPARE(attachment.iconName(), updatedAttachmentIconNames.at(i)); 0689 } 0690 QCOMPARE(task->isRunning(), updatedRunning); 0691 } 0692 0693 void shouldUpdateTaskRecurrenceFromItem_data() 0694 { 0695 QTest::addColumn<int>("todoRecurrence"); 0696 QTest::addColumn<Domain::Task::Recurrence>("expectedRecurrence"); 0697 0698 QTest::newRow("none") << int(KCalendarCore::Recurrence::rNone) << Domain::Task::NoRecurrence; 0699 QTest::newRow("minutely") << int(KCalendarCore::Recurrence::rMinutely) << Domain::Task::NoRecurrence; 0700 QTest::newRow("hourly") << int(KCalendarCore::Recurrence::rHourly) << Domain::Task::NoRecurrence; 0701 QTest::newRow("daily") << int(KCalendarCore::Recurrence::rDaily) << Domain::Task::RecursDaily; 0702 QTest::newRow("weekly") << int(KCalendarCore::Recurrence::rWeekly) << Domain::Task::RecursWeekly; 0703 QTest::newRow("monthly") << int(KCalendarCore::Recurrence::rMonthlyDay) << Domain::Task::RecursMonthly; 0704 QTest::newRow("yearly") << int(KCalendarCore::Recurrence::rYearlyMonth) << Domain::Task::RecursYearly; 0705 } 0706 0707 void shouldUpdateTaskRecurrenceFromItem() 0708 { 0709 // GIVEN 0710 0711 // A todo... 0712 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 0713 todo->setSummary(QStringLiteral("summary")); 0714 0715 QFETCH(int, todoRecurrence); 0716 switch (todoRecurrence) { 0717 case KCalendarCore::Recurrence::rNone: 0718 break; 0719 case KCalendarCore::Recurrence::rMinutely: 0720 todo->recurrence()->setMinutely(1); 0721 break; 0722 case KCalendarCore::Recurrence::rHourly: 0723 todo->recurrence()->setHourly(1); 0724 break; 0725 case KCalendarCore::Recurrence::rDaily: 0726 todo->recurrence()->setDaily(1); 0727 break; 0728 case KCalendarCore::Recurrence::rWeekly: 0729 todo->recurrence()->setWeekly(1); 0730 break; 0731 case KCalendarCore::Recurrence::rMonthlyDay: 0732 todo->recurrence()->setMonthly(1); 0733 break; 0734 case KCalendarCore::Recurrence::rYearlyMonth: 0735 todo->recurrence()->setYearly(1); 0736 break; 0737 default: 0738 qFatal("Shouldn't happen"); 0739 } 0740 0741 // ... as payload of an item... 0742 Akonadi::Item item; 0743 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0744 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 0745 0746 // ... which has a parent collection... 0747 Akonadi::Collection collection(43); 0748 item.setParentCollection(collection); 0749 0750 // WHEN 0751 // ... deserialized as a task 0752 Akonadi::Serializer serializer; 0753 auto task = serializer.createTaskFromItem(item); 0754 0755 // THEN 0756 QFETCH(Domain::Task::Recurrence, expectedRecurrence); 0757 QCOMPARE(task->recurrence(), expectedRecurrence); 0758 } 0759 0760 void shouldNotBreakRecurrenceDuringSerialization() 0761 { 0762 // GIVEN 0763 0764 // Data... 0765 const QDate today(QDate::currentDate()); 0766 const QDate doneDate(2013, 11, 20); 0767 const QDate startDate(2013, 11, 10); 0768 0769 // ... stored in a todo... 0770 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 0771 todo->setSummary(QStringLiteral("summary")); 0772 todo->setDtStart(startDate.startOfDay()); 0773 todo->recurrence()->setMonthly(1); 0774 0775 // ... as payload of an item... 0776 Akonadi::Item item; 0777 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0778 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 0779 0780 // ... deserialized as a task 0781 Akonadi::Serializer serializer; 0782 auto task = serializer.createTaskFromItem(item); 0783 0784 // WHEN 0785 // Task is marked done... 0786 task->setDoneDate(doneDate); 0787 task->setDone(true); 0788 0789 // and goes through serialization and back 0790 const auto newItem = serializer.createItemFromTask(task); 0791 serializer.updateTaskFromItem(task, newItem); 0792 0793 // THEN 0794 QCOMPARE(task->recurrence(), Domain::Task::RecursMonthly); 0795 QVERIFY(!task->isDone()); 0796 const QDate lastOccurrence(QDate(today.year(), today.month(), 10)); 0797 if (today.day() > 10) 0798 QCOMPARE(task->startDate(), lastOccurrence.addMonths(1)); 0799 else 0800 QCOMPARE(task->startDate(), lastOccurrence); 0801 } 0802 0803 void shouldNotUpdateTaskFromInvalidItem() 0804 { 0805 // GIVEN 0806 0807 // Data... 0808 const QString summary = QStringLiteral("summary"); 0809 const QString content = QStringLiteral("content"); 0810 const bool isDone = true; 0811 const QDate doneDate(2013, 11, 30); 0812 const QDate startDate(2013, 11, 24); 0813 const QDate dueDate(2014, 03, 01); 0814 0815 // ... stored in a todo... 0816 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 0817 originalTodo->setSummary(summary); 0818 originalTodo->setDescription(content); 0819 0820 if (originalTodo) 0821 originalTodo->setCompleted(doneDate.startOfDay()); 0822 else 0823 originalTodo->setCompleted(isDone); 0824 setTodoDates(originalTodo, startDate, dueDate); 0825 0826 // ... as payload of an item... 0827 Akonadi::Item originalItem; 0828 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0829 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 0830 0831 // ... deserialized as a task 0832 Akonadi::Serializer serializer; 0833 auto task = serializer.createTaskFromItem(originalItem); 0834 0835 // WHEN 0836 Akonadi::Item invalidItem; 0837 serializer.updateTaskFromItem(task, invalidItem); 0838 0839 // THEN 0840 QCOMPARE(task->title(), summary); 0841 QCOMPARE(task->text(), content); 0842 QCOMPARE(task->isDone(), isDone); 0843 QCOMPARE(task->doneDate(), doneDate); 0844 QCOMPARE(task->startDate(), startDate); 0845 QCOMPARE(task->dueDate(), dueDate); 0846 QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); 0847 } 0848 0849 void shouldNotUpdateTaskFromProjectItem() 0850 { 0851 // GIVEN 0852 0853 // Data... 0854 const QString summary = QStringLiteral("summary"); 0855 const QString content = QStringLiteral("content"); 0856 const bool isDone = true; 0857 const QDate doneDate(2013, 11, 30); 0858 const QDate startDate(2013, 11, 24); 0859 const QDate dueDate(2014, 03, 01); 0860 0861 // ... stored in a todo... 0862 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 0863 originalTodo->setSummary(summary); 0864 originalTodo->setDescription(content); 0865 0866 if (originalTodo) 0867 originalTodo->setCompleted(doneDate.startOfDay()); 0868 else 0869 originalTodo->setCompleted(isDone); 0870 setTodoDates(originalTodo, startDate, dueDate); 0871 0872 // ... as payload of an item... 0873 Akonadi::Item originalItem; 0874 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0875 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 0876 0877 // ... deserialized as a task 0878 Akonadi::Serializer serializer; 0879 auto task = serializer.createTaskFromItem(originalItem); 0880 0881 // WHEN 0882 // A todo with the project flag 0883 KCalendarCore::Todo::Ptr projectTodo(new KCalendarCore::Todo); 0884 projectTodo->setSummary(QStringLiteral("foo")); 0885 projectTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 0886 0887 // ... as payload of an item 0888 Akonadi::Item projectItem; 0889 projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 0890 projectItem.setPayload<KCalendarCore::Todo::Ptr>(projectTodo); 0891 serializer.updateTaskFromItem(task, projectItem); 0892 0893 // THEN 0894 QCOMPARE(task->title(), summary); 0895 QCOMPARE(task->text(), content); 0896 QCOMPARE(task->isDone(), isDone); 0897 QCOMPARE(task->doneDate(), doneDate); 0898 QCOMPARE(task->startDate(), startDate); 0899 QCOMPARE(task->dueDate(), dueDate); 0900 QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); 0901 } 0902 0903 void shouldCreateItemFromTask_data() 0904 { 0905 QTest::addColumn<QString>("summary"); 0906 QTest::addColumn<QString>("content"); 0907 QTest::addColumn<bool>("isDone"); 0908 QTest::addColumn<QDate>("doneDate"); 0909 QTest::addColumn<QDate>("startDate"); 0910 QTest::addColumn<QDate>("dueDate"); 0911 QTest::addColumn<qint64>("itemId"); 0912 QTest::addColumn<qint64>("parentCollectionId"); 0913 QTest::addColumn<QString>("todoUid"); 0914 QTest::addColumn<Domain::Task::Recurrence>("recurrence"); 0915 QTest::addColumn<Domain::Task::Attachments>("attachments"); 0916 QTest::addColumn<bool>("running"); 0917 QTest::addColumn<QStringList>("contexts"); 0918 0919 Domain::Task::Attachments attachments; 0920 0921 Domain::Task::Attachment dataAttachment; 0922 dataAttachment.setData("foo"); 0923 dataAttachment.setLabel("dataAttachment"); 0924 dataAttachment.setMimeType("text/plain"); 0925 dataAttachment.setIconName("text-plain"); 0926 attachments.append(dataAttachment); 0927 0928 Domain::Task::Attachment uriAttachment; 0929 uriAttachment.setUri(QUrl("https://www.kde.org")); 0930 uriAttachment.setLabel("uriAttachment"); 0931 uriAttachment.setMimeType("text/html"); 0932 uriAttachment.setIconName("text-html"); 0933 attachments.append(uriAttachment); 0934 0935 QTest::newRow("nominal case (no id)") << "summary" << "content" << false << QDate() 0936 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0937 << qint64(-1) << qint64(-1) << QString() 0938 << Domain::Task::NoRecurrence 0939 << attachments 0940 << false 0941 << QStringList(); 0942 QTest::newRow("nominal case (daily)") << "summary" << "content" << false << QDate() 0943 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0944 << qint64(-1) << qint64(-1) << QString() 0945 << Domain::Task::RecursDaily 0946 << Domain::Task::Attachments() 0947 << false 0948 << QStringList(); 0949 QTest::newRow("nominal case (weekly)") << "summary" << "content" << false << QDate() 0950 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0951 << qint64(-1) << qint64(-1) << QString() 0952 << Domain::Task::RecursWeekly 0953 << Domain::Task::Attachments() 0954 << false 0955 << QStringList(); 0956 QTest::newRow("nominal case (monthly)") << "summary" << "content" << false << QDate() 0957 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0958 << qint64(-1) << qint64(-1) << QString() 0959 << Domain::Task::RecursMonthly 0960 << Domain::Task::Attachments() 0961 << false 0962 << QStringList(); 0963 QTest::newRow("nominal case (yearly)") << "summary" << "content" << false << QDate() 0964 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0965 << qint64(-1) << qint64(-1) << QString() 0966 << Domain::Task::RecursYearly 0967 << Domain::Task::Attachments() 0968 << false 0969 << QStringList(); 0970 QTest::newRow("done case (no id)") << "summary" << "content" << true << QDate(2013, 11, 30) 0971 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0972 << qint64(-1) << qint64(-1) << QString() 0973 << Domain::Task::NoRecurrence 0974 << Domain::Task::Attachments() 0975 << false 0976 << QStringList(); 0977 QTest::newRow("empty case (no id)") << QString() << QString() << false << QDate() 0978 << QDate() << QDate() 0979 << qint64(-1) << qint64(-1) << QString() 0980 << Domain::Task::NoRecurrence 0981 << Domain::Task::Attachments() 0982 << false 0983 << QStringList(); 0984 #if 0 // if we ever need time info, then we need a Task::setAllDay(bool) just like KCalendarCore::Todo has. 0985 QTest::newRow("nominal_with_time_info_noid") << "summary" << "content" << true << QDateTime(QDate(2015, 3, 1), QTime(1, 2, 3), Qt::UTC) 0986 << QDateTime(QDate(2013, 11, 24), QTime(0, 1, 2), Qt::UTC) << QDateTime(QDate(2016, 3, 1), QTime(4, 5, 6), Qt::UTC) 0987 << qint64(-1) << qint64(-1) << QString() 0988 << Domain::Task::NoRecurrence 0989 << Domain::Task::Attachments() 0990 << false 0991 << QStringList(); 0992 #endif 0993 0994 QTest::newRow("nominal case (with id)") << "summary" << "content" << false << QDate() 0995 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 0996 << qint64(42) << qint64(43) << "my-uid" 0997 << Domain::Task::NoRecurrence 0998 << Domain::Task::Attachments() 0999 << false 1000 << QStringList(); 1001 QTest::newRow("done case (with id)") << "summary" << "content" << true << QDate(2013, 11, 30) 1002 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 1003 << qint64(42) << qint64(43) << "my-uid" 1004 << Domain::Task::NoRecurrence 1005 << Domain::Task::Attachments() 1006 << false 1007 << QStringList(); 1008 QTest::newRow("empty case (with id)") << QString() << QString() << false << QDate() 1009 << QDate() << QDate() 1010 << qint64(42) << qint64(43) << "my-uid" 1011 << Domain::Task::NoRecurrence 1012 << Domain::Task::Attachments() 1013 << false 1014 << QStringList(); 1015 QTest::newRow("nominal case (running)") << "running" << QString() << false << QDate() 1016 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 1017 << qint64(-1) << qint64(-1) << QString() 1018 << Domain::Task::NoRecurrence 1019 << Domain::Task::Attachments() 1020 << true 1021 << QStringList(); 1022 QTest::newRow("with_context") << "with_context" << QString() << false << QDate() 1023 << QDate(2013, 11, 24) << QDate(2014, 03, 01) 1024 << qint64(-1) << qint64(-1) << QString() 1025 << Domain::Task::NoRecurrence 1026 << Domain::Task::Attachments() 1027 << true 1028 << QStringList({"c1", "c2"}); 1029 } 1030 1031 void shouldCreateItemFromTask() 1032 { 1033 // GIVEN 1034 1035 // Data... 1036 QFETCH(QString, summary); 1037 QFETCH(QString, content); 1038 QFETCH(bool, isDone); 1039 QFETCH(QDate, doneDate); 1040 QFETCH(QDate, startDate); 1041 QFETCH(QDate, dueDate); 1042 QFETCH(qint64, itemId); 1043 QFETCH(qint64, parentCollectionId); 1044 QFETCH(QString, todoUid); 1045 QFETCH(Domain::Task::Recurrence, recurrence); 1046 QFETCH(Domain::Task::Attachments, attachments); 1047 QFETCH(bool, running); 1048 QFETCH(QStringList, contexts); 1049 1050 // ... stored in a task 1051 auto task = Domain::Task::Ptr::create(); 1052 task->setTitle(summary); 1053 task->setText(content); 1054 task->setDone(isDone); 1055 task->setDoneDate(doneDate); 1056 task->setStartDate(startDate); 1057 task->setDueDate(dueDate); 1058 task->setRecurrence(recurrence); 1059 task->setAttachments(attachments); 1060 task->setRunning(running); 1061 1062 if (itemId > 0) 1063 task->setProperty("itemId", itemId); 1064 1065 if (parentCollectionId > 0) 1066 task->setProperty("parentCollectionId", parentCollectionId); 1067 1068 if (!todoUid.isEmpty()) 1069 task->setProperty("todoUid", todoUid); 1070 1071 task->setProperty("relatedUid", "parent-uid"); 1072 task->setProperty("contextUids", contexts); 1073 1074 // WHEN 1075 Akonadi::Serializer serializer; 1076 auto item = serializer.createItemFromTask(task); 1077 1078 // THEN 1079 QCOMPARE(item.mimeType(), KCalendarCore::Todo::todoMimeType()); 1080 1081 QCOMPARE(item.isValid(), itemId > 0); 1082 if (itemId > 0) { 1083 QCOMPARE(item.id(), itemId); 1084 } 1085 1086 QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0); 1087 if (parentCollectionId > 0) { 1088 QCOMPARE(item.parentCollection().id(), parentCollectionId); 1089 } 1090 1091 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 1092 QCOMPARE(todo->summary(), summary); 1093 QCOMPARE(todo->description(), content); 1094 QCOMPARE(todo->isCompleted(), isDone); 1095 QCOMPARE(todo->completed().toLocalTime().date(), doneDate); 1096 QCOMPARE(todo->dtStart().toLocalTime().date(), startDate); 1097 QCOMPARE(todo->dtDue().toLocalTime().date(), dueDate); 1098 if (todo->dtStart().isValid()) { 1099 QCOMPARE(int(todo->dtStart().timeSpec()), int(Qt::LocalTime)); 1100 } 1101 QVERIFY(todo->allDay()); // this is always true currently... 1102 const ushort expectedRecurrence = recurrence == Domain::Task::NoRecurrence ? KCalendarCore::Recurrence::rNone 1103 : recurrence == Domain::Task::RecursDaily ? KCalendarCore::Recurrence::rDaily 1104 : recurrence == Domain::Task::RecursWeekly ? KCalendarCore::Recurrence::rWeekly 1105 : recurrence == Domain::Task::RecursMonthly ? KCalendarCore::Recurrence::rMonthlyDay 1106 : recurrence == Domain::Task::RecursYearly ? KCalendarCore::Recurrence::rYearlyMonth 1107 : KCalendarCore::Recurrence::rNone; // Shouldn't happen though 1108 QCOMPARE(todo->recurrence()->recurrenceType(), expectedRecurrence); 1109 if (recurrence != Domain::Task::NoRecurrence) 1110 QCOMPARE(todo->recurrence()->frequency(), 1); 1111 1112 QCOMPARE(todo->attachments().size(), attachments.size()); 1113 for (int i = 0; i < attachments.size(); i++) { 1114 auto attachment = todo->attachments().at(i); 1115 QCOMPARE(attachment.isUri(), attachments.at(i).isUri()); 1116 QCOMPARE(QUrl(attachment.uri()), attachments.at(i).uri()); 1117 QCOMPARE(attachment.decodedData(), attachments.at(i).data()); 1118 QCOMPARE(attachment.label(), attachments.at(i).label()); 1119 QCOMPARE(attachment.mimeType(), attachments.at(i).mimeType()); 1120 } 1121 1122 if (!todoUid.isEmpty()) { 1123 QCOMPARE(todo->uid(), todoUid); 1124 } 1125 1126 QCOMPARE(todo->relatedTo(), QStringLiteral("parent-uid")); 1127 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsRunning()), running ? QStringLiteral("1") : QString()); 1128 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), contexts.join(',')); 1129 } 1130 1131 void shouldVerifyIfAnItemIsATaskChild_data() 1132 { 1133 QTest::addColumn<Domain::Task::Ptr>("task"); 1134 QTest::addColumn<Akonadi::Item>("item"); 1135 QTest::addColumn<bool>("isParent"); 1136 1137 // Create task 1138 const QString summary = QStringLiteral("summary"); 1139 const QString content = QStringLiteral("content"); 1140 const bool isDone = true; 1141 const QDate doneDate(QDate(2013, 11, 30)); 1142 const QDate startDate(QDate(2013, 11, 24)); 1143 const QDate dueDate(QDate(2014, 03, 01)); 1144 1145 // ... create a task 1146 Domain::Task::Ptr task(new Domain::Task); 1147 task->setTitle(summary); 1148 task->setText(content); 1149 task->setDone(isDone); 1150 task->setDoneDate(doneDate); 1151 task->setStartDate(startDate); 1152 task->setDueDate(dueDate); 1153 task->setProperty("todoUid", "1"); 1154 1155 // Create Child item 1156 KCalendarCore::Todo::Ptr childTodo(new KCalendarCore::Todo); 1157 childTodo->setSummary(summary); 1158 childTodo->setDescription(content); 1159 1160 if (isDone) 1161 childTodo->setCompleted(doneDate.startOfDay()); 1162 else 1163 childTodo->setCompleted(isDone); 1164 1165 setTodoDates(childTodo, startDate, dueDate); 1166 1167 Akonadi::Item childItem; 1168 childItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1169 childItem.setPayload<KCalendarCore::Todo::Ptr>(childTodo); 1170 1171 QTest::newRow("without parent") << task << childItem << false; 1172 1173 // Create Child Item with parent 1174 KCalendarCore::Todo::Ptr childTodo2(new KCalendarCore::Todo); 1175 childTodo2->setSummary(summary); 1176 childTodo2->setDescription(content); 1177 1178 if (isDone) 1179 childTodo2->setCompleted(doneDate.startOfDay()); 1180 else 1181 childTodo2->setCompleted(isDone); 1182 setTodoDates(childTodo2, startDate, dueDate); 1183 childTodo2->setRelatedTo(QStringLiteral("1")); 1184 1185 Akonadi::Item childItem2; 1186 childItem2.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1187 childItem2.setPayload<KCalendarCore::Todo::Ptr>(childTodo2); 1188 1189 QTest::newRow("with parent") << task << childItem2 << true; 1190 1191 Domain::Task::Ptr invalidTask(new Domain::Task); 1192 QTest::newRow("with invalid task") << invalidTask << childItem << false; 1193 1194 Akonadi::Item invalidItem; 1195 QTest::newRow("with invalid item") << task << invalidItem << false; 1196 1197 } 1198 1199 void shouldVerifyIfAnItemIsATaskChild() 1200 { 1201 // GIVEN 1202 QFETCH(Domain::Task::Ptr, task); 1203 QFETCH(Akonadi::Item, item); 1204 QFETCH(bool, isParent); 1205 1206 // WHEN 1207 Akonadi::Serializer serializer; 1208 bool value = serializer.isTaskChild(task, item); 1209 1210 // THEN 1211 QCOMPARE(value, isParent); 1212 } 1213 1214 void shouldRetrieveRelatedUidFromItem_data() 1215 { 1216 QTest::addColumn<Akonadi::Item>("item"); 1217 QTest::addColumn<QString>("expectedUid"); 1218 1219 Akonadi::Item item1; 1220 KCalendarCore::Todo::Ptr todo1(new KCalendarCore::Todo); 1221 item1.setPayload<KCalendarCore::Todo::Ptr>(todo1); 1222 1223 Akonadi::Item item2; 1224 KCalendarCore::Todo::Ptr todo2(new KCalendarCore::Todo); 1225 todo2->setRelatedTo(QStringLiteral("1")); 1226 item2.setPayload<KCalendarCore::Todo::Ptr>(todo2); 1227 1228 QTest::newRow("task without related") << item1 << QString(); 1229 QTest::newRow("task with related") << item2 << "1"; 1230 } 1231 1232 void shouldRetrieveRelatedUidFromItem() 1233 { 1234 // GIVEN 1235 QFETCH(Akonadi::Item, item); 1236 QFETCH(QString, expectedUid); 1237 1238 // WHEN 1239 Akonadi::Serializer serializer; 1240 QString uid = serializer.relatedUidFromItem(item); 1241 1242 // THEN 1243 QCOMPARE(uid, expectedUid); 1244 } 1245 1246 void shouldCreateNoteFromItem_data() 1247 { 1248 QTest::addColumn<QString>("title"); 1249 QTest::addColumn<QString>("text"); 1250 QTest::addColumn<QString>("relatedUid"); 1251 1252 QTest::newRow("nominal case (no related)") << "A note title" << "A note content.\nWith two lines." << QString(); 1253 QTest::newRow("nominal case (with related)") << "A note title" << "A note content.\nWith two lines." << "parent-uid"; 1254 QTest::newRow("trailing new lines") << "A note title" << "Empty lines at the end.\n\n\n" << QString(); 1255 QTest::newRow("empty case") << QString() << QString() << QString(); 1256 } 1257 1258 void shouldCreateProjectFromItem_data() 1259 { 1260 QTest::addColumn<QString>("summary"); 1261 1262 QTest::newRow("nominal case") << "summary"; 1263 QTest::newRow("empty case") << QString(); 1264 } 1265 1266 void shouldCreateProjectFromItem() 1267 { 1268 // GIVEN 1269 1270 // Data... 1271 QFETCH(QString, summary); 1272 1273 // ... stored in a todo... 1274 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1275 todo->setSummary(summary); 1276 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1277 QVERIFY(!todo->uid().isEmpty()); 1278 1279 // ... as payload of an item 1280 Akonadi::Item item(42); 1281 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1282 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1283 1284 // which has a parent collection 1285 Akonadi::Collection collection(43); 1286 item.setParentCollection(collection); 1287 1288 // WHEN 1289 Akonadi::Serializer serializer; 1290 Domain::Project::Ptr project = serializer.createProjectFromItem(item); 1291 1292 // THEN 1293 QCOMPARE(project->name(), summary); 1294 QCOMPARE(project->property("itemId").toLongLong(), item.id()); 1295 QCOMPARE(project->property("parentCollectionId").toLongLong(), collection.id()); 1296 QCOMPARE(project->property("todoUid").toString(), todo->uid()); 1297 } 1298 1299 void shouldCreateNullProjectFromInvalidItem() 1300 { 1301 // GIVEN 1302 Akonadi::Item item; 1303 1304 // WHEN 1305 Akonadi::Serializer serializer; 1306 Domain::Project::Ptr project = serializer.createProjectFromItem(item); 1307 1308 // THEN 1309 QVERIFY(project.isNull()); 1310 } 1311 1312 void shouldCreateNullProjectFromTaskItem() 1313 { 1314 // GIVEN 1315 1316 // A todo without the project flag 1317 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1318 todo->setSummary(QStringLiteral("foo")); 1319 1320 // ... as payload of an item 1321 Akonadi::Item item; 1322 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1323 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1324 1325 // WHEN 1326 Akonadi::Serializer serializer; 1327 Domain::Project::Ptr project = serializer.createProjectFromItem(item); 1328 1329 // THEN 1330 QVERIFY(project.isNull()); 1331 } 1332 1333 void shouldUpdateProjectFromItem_data() 1334 { 1335 QTest::addColumn<QString>("updatedSummary"); 1336 1337 QTest::newRow("no change") << "summary"; 1338 QTest::newRow("changed") << "new summary"; 1339 } 1340 1341 void shouldUpdateProjectFromItem() 1342 { 1343 // GIVEN 1344 1345 // A todo... 1346 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 1347 originalTodo->setSummary(QStringLiteral("summary")); 1348 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1349 1350 // ... as payload of an item... 1351 Akonadi::Item originalItem(42); 1352 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1353 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 1354 1355 // ... which has a parent collection... 1356 Akonadi::Collection originalCollection(43); 1357 originalItem.setParentCollection(originalCollection); 1358 1359 // ... deserialized as a project 1360 Akonadi::Serializer serializer; 1361 auto project = serializer.createProjectFromItem(originalItem); 1362 1363 // WHEN 1364 1365 // Data... 1366 QFETCH(QString, updatedSummary); 1367 1368 // ... in a new todo... 1369 KCalendarCore::Todo::Ptr updatedTodo(new KCalendarCore::Todo); 1370 updatedTodo->setSummary(updatedSummary); 1371 updatedTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1372 QVERIFY(!updatedTodo->uid().isEmpty()); 1373 1374 // ... as payload of a new item 1375 Akonadi::Item updatedItem(44); 1376 updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1377 updatedItem.setPayload<KCalendarCore::Todo::Ptr>(updatedTodo); 1378 1379 // ... which has a new parent collection 1380 Akonadi::Collection updatedCollection(45); 1381 updatedItem.setParentCollection(updatedCollection); 1382 1383 serializer.updateProjectFromItem(project, updatedItem); 1384 1385 // THEN 1386 QCOMPARE(project->name(), updatedSummary); 1387 QCOMPARE(project->property("itemId").toLongLong(), updatedItem.id()); 1388 QCOMPARE(project->property("parentCollectionId").toLongLong(), updatedCollection.id()); 1389 QCOMPARE(project->property("todoUid").toString(), updatedTodo->uid()); 1390 } 1391 1392 void shouldNotUpdateProjectFromInvalidItem() 1393 { 1394 // GIVEN 1395 1396 // Data... 1397 const QString summary = QStringLiteral("summary"); 1398 1399 // ... stored in a todo... 1400 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 1401 originalTodo->setSummary(summary); 1402 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1403 1404 // ... as payload of an item... 1405 Akonadi::Item originalItem; 1406 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1407 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 1408 1409 // ... deserialized as a project 1410 Akonadi::Serializer serializer; 1411 auto project = serializer.createProjectFromItem(originalItem); 1412 1413 // WHEN 1414 Akonadi::Item invalidItem; 1415 serializer.updateProjectFromItem(project, invalidItem); 1416 1417 // THEN 1418 QCOMPARE(project->name(), summary); 1419 } 1420 1421 void shouldNotUpdateProjectFromTaskItem() 1422 { 1423 // GIVEN 1424 1425 // Data... 1426 const QString summary = QStringLiteral("summary"); 1427 1428 // ... stored in a todo... 1429 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 1430 originalTodo->setSummary(summary); 1431 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1432 1433 // ... as payload of an item... 1434 Akonadi::Item originalItem; 1435 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1436 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 1437 1438 // ... deserialized as a project 1439 Akonadi::Serializer serializer; 1440 auto project = serializer.createProjectFromItem(originalItem); 1441 1442 // WHEN 1443 // A todo without the project flag 1444 KCalendarCore::Todo::Ptr projectTodo(new KCalendarCore::Todo); 1445 projectTodo->setSummary(QStringLiteral("foo")); 1446 1447 // ... as payload of an item 1448 Akonadi::Item projectItem; 1449 projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1450 projectItem.setPayload<KCalendarCore::Todo::Ptr>(projectTodo); 1451 serializer.updateProjectFromItem(project, projectItem); 1452 1453 // THEN 1454 QCOMPARE(project->name(), summary); 1455 } 1456 1457 void shouldCreateItemFromProject_data() 1458 { 1459 QTest::addColumn<QString>("summary"); 1460 QTest::addColumn<qint64>("itemId"); 1461 QTest::addColumn<qint64>("parentCollectionId"); 1462 1463 QTest::newRow("nominal case (no id)") << "summary" << qint64(-1) << qint64(-1); 1464 QTest::newRow("empty case (no id)") << QString() << qint64(-1) << qint64(-1); 1465 1466 QTest::newRow("nominal case (with id)") << "summary" << qint64(42) << qint64(43); 1467 QTest::newRow("empty case (with id)") << QString() << qint64(42) << qint64(43); 1468 } 1469 1470 void shouldCreateItemFromProject() 1471 { 1472 // GIVEN 1473 1474 // Data... 1475 QFETCH(QString, summary); 1476 QFETCH(qint64, itemId); 1477 QFETCH(qint64, parentCollectionId); 1478 const QString todoUid = QStringLiteral("test-uid"); 1479 1480 // ... stored in a project 1481 auto project = Domain::Project::Ptr::create(); 1482 project->setName(summary); 1483 project->setProperty("todoUid", todoUid); 1484 1485 if (itemId > 0) 1486 project->setProperty("itemId", itemId); 1487 1488 if (parentCollectionId > 0) 1489 project->setProperty("parentCollectionId", parentCollectionId); 1490 1491 // WHEN 1492 Akonadi::Serializer serializer; 1493 auto item = serializer.createItemFromProject(project); 1494 1495 // THEN 1496 QCOMPARE(item.mimeType(), KCalendarCore::Todo::todoMimeType()); 1497 1498 QCOMPARE(item.isValid(), itemId > 0); 1499 if (itemId > 0) { 1500 QCOMPARE(item.id(), itemId); 1501 } 1502 1503 QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0); 1504 if (parentCollectionId > 0) { 1505 QCOMPARE(item.parentCollection().id(), parentCollectionId); 1506 } 1507 1508 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 1509 QCOMPARE(todo->summary(), summary); 1510 QCOMPARE(todo->uid(), todoUid); 1511 QVERIFY(!todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject()).isEmpty()); 1512 } 1513 1514 void shouldVerifyIfAnItemIsAProjectChild_data() 1515 { 1516 QTest::addColumn<Domain::Project::Ptr>("project"); 1517 QTest::addColumn<Akonadi::Item>("item"); 1518 QTest::addColumn<bool>("isParent"); 1519 1520 // Create project 1521 auto project = Domain::Project::Ptr::create(); 1522 project->setName(QStringLiteral("project")); 1523 project->setProperty("todoUid", "1"); 1524 1525 // Create unrelated todo 1526 auto unrelatedTodo = KCalendarCore::Todo::Ptr::create(); 1527 unrelatedTodo->setSummary(QStringLiteral("summary")); 1528 Akonadi::Item unrelatedTodoItem; 1529 unrelatedTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1530 unrelatedTodoItem.setPayload<KCalendarCore::Todo::Ptr>(unrelatedTodo); 1531 1532 QTest::newRow("unrelated todo") << project << unrelatedTodoItem << false; 1533 1534 // Create child todo 1535 auto childTodo = KCalendarCore::Todo::Ptr::create(); 1536 childTodo->setSummary(QStringLiteral("summary")); 1537 childTodo->setRelatedTo(QStringLiteral("1")); 1538 Akonadi::Item childTodoItem; 1539 childTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1540 childTodoItem.setPayload<KCalendarCore::Todo::Ptr>(childTodo); 1541 1542 QTest::newRow("child todo") << project << childTodoItem << true; 1543 1544 auto invalidProject = Domain::Project::Ptr::create(); 1545 QTest::newRow("invalid project") << invalidProject << unrelatedTodoItem << false; 1546 1547 Akonadi::Item invalidItem; 1548 QTest::newRow("invalid item") << project << invalidItem << false; 1549 1550 } 1551 1552 void shouldVerifyIfAnItemIsAProjectChild() 1553 { 1554 // GIVEN 1555 QFETCH(Domain::Project::Ptr, project); 1556 QFETCH(Akonadi::Item, item); 1557 QFETCH(bool, isParent); 1558 1559 // WHEN 1560 Akonadi::Serializer serializer; 1561 bool value = serializer.isProjectChild(project, item); 1562 1563 // THEN 1564 QCOMPARE(value, isParent); 1565 } 1566 1567 void shouldUpdateItemParent_data() 1568 { 1569 QTest::addColumn<Akonadi::Item>("item"); 1570 QTest::addColumn<Domain::Task::Ptr>("parent"); 1571 QTest::addColumn<QString>("expectedRelatedToUid"); 1572 1573 Akonadi::Item item1; 1574 KCalendarCore::Todo::Ptr todo1(new KCalendarCore::Todo); 1575 item1.setPayload<KCalendarCore::Todo::Ptr>(todo1); 1576 1577 Domain::Task::Ptr parent(new Domain::Task); 1578 parent->setProperty("todoUid", "1"); 1579 1580 QTest::newRow("nominal case") << item1 << parent << "1"; 1581 1582 Akonadi::Item item2; 1583 QTest::newRow("update item without payload") << item2 << parent << QString(); 1584 1585 Domain::Task::Ptr parent2(new Domain::Task); 1586 QTest::newRow("update item with a empty parent uid") << item1 << parent2 << QString(); 1587 } 1588 1589 void shouldUpdateItemParent() 1590 { 1591 // GIVEN 1592 QFETCH(Akonadi::Item, item); 1593 QFETCH(Domain::Task::Ptr, parent); 1594 QFETCH(QString, expectedRelatedToUid); 1595 1596 // WHEN 1597 Akonadi::Serializer serializer; 1598 serializer.updateItemParent(item, parent); 1599 1600 // THEN 1601 if (item.hasPayload<KCalendarCore::Todo::Ptr>()) { 1602 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 1603 QString relatedUid = todo->relatedTo(); 1604 QCOMPARE(relatedUid, expectedRelatedToUid); 1605 } 1606 } 1607 1608 void shouldUpdateItemProject_data() 1609 { 1610 QTest::addColumn<Akonadi::Item>("item"); 1611 QTest::addColumn<Domain::Project::Ptr>("parent"); 1612 QTest::addColumn<QString>("expectedRelatedToUid"); 1613 1614 Akonadi::Item todoItem; 1615 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1616 todoItem.setPayload<KCalendarCore::Todo::Ptr>(todo); 1617 1618 auto parent = Domain::Project::Ptr::create(); 1619 parent->setProperty("todoUid", "1"); 1620 1621 QTest::newRow("nominal todo case") << todoItem << parent << "1"; 1622 1623 auto invalidParent = Domain::Project::Ptr::create(); 1624 QTest::newRow("update todo item with a empty parent uid") << todoItem << invalidParent << QString(); 1625 1626 Akonadi::Item invalidItem; 1627 QTest::newRow("update item without payload") << invalidItem << parent << QString(); 1628 } 1629 1630 void shouldUpdateItemProject() 1631 { 1632 // GIVEN 1633 QFETCH(Akonadi::Item, item); 1634 QFETCH(Domain::Project::Ptr, parent); 1635 QFETCH(QString, expectedRelatedToUid); 1636 1637 // WHEN 1638 Akonadi::Serializer serializer; 1639 serializer.updateItemProject(item, parent); 1640 1641 // THEN 1642 if (item.hasPayload<KCalendarCore::Todo::Ptr>()) { 1643 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 1644 const QString relatedUid = todo->relatedTo(); 1645 QCOMPARE(relatedUid, expectedRelatedToUid); 1646 } 1647 } 1648 1649 void shouldFilterChildrenItem_data() 1650 { 1651 QTest::addColumn<Akonadi::Item>("item"); 1652 QTest::addColumn<Akonadi::Item::List>("items"); 1653 QTest::addColumn<int>("size"); 1654 1655 Akonadi::Item item(12); 1656 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1657 todo->setUid(QStringLiteral("1")); 1658 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1659 Akonadi::Item::List items; 1660 1661 QTest::newRow("empty list") << item << items << 0; 1662 1663 Akonadi::Item item2(13); 1664 KCalendarCore::Todo::Ptr todo2(new KCalendarCore::Todo); 1665 item2.setPayload<KCalendarCore::Todo::Ptr>(todo2); 1666 Akonadi::Item::List items2; 1667 items2 << item2; 1668 1669 QTest::newRow("list without child") << item << items2 << 0; 1670 1671 Akonadi::Item item3(14); 1672 KCalendarCore::Todo::Ptr todo3(new KCalendarCore::Todo); 1673 todo3->setUid(QStringLiteral("3")); 1674 todo3->setRelatedTo(QStringLiteral("1")); 1675 item3.setPayload<KCalendarCore::Todo::Ptr>(todo3); 1676 Akonadi::Item::List items3; 1677 items3 << item2 << item3; 1678 1679 QTest::newRow("list with child") << item << items3 << 1; 1680 1681 Akonadi::Item item4(15); 1682 KCalendarCore::Todo::Ptr todo4(new KCalendarCore::Todo); 1683 todo4->setRelatedTo(QStringLiteral("3")); 1684 item4.setPayload<KCalendarCore::Todo::Ptr>(todo4); 1685 Akonadi::Item::List items4; 1686 items4 << item2 << item3 << item4; 1687 1688 QTest::newRow("list with child with a child") << item << items4 << 2; 1689 1690 Akonadi::Item::List items5; 1691 items5 << item << item2 << item3 << item4; 1692 QTest::newRow("list with filter in list") << item << items5 << 2; 1693 } 1694 1695 void shouldFilterChildrenItem() 1696 { 1697 // GIVEN 1698 QFETCH(Akonadi::Item, item); 1699 QFETCH(Akonadi::Item::List, items); 1700 QFETCH(int, size); 1701 1702 // WHEN 1703 Akonadi::Serializer serializer; 1704 Akonadi::Item::List list = serializer.filterDescendantItems(items, item); 1705 1706 // THEN 1707 QCOMPARE(list.size(), size); 1708 } 1709 1710 void shouldRemoveItemParent_data() 1711 { 1712 QTest::addColumn<Akonadi::Item>("item"); 1713 1714 Akonadi::Item item(15); 1715 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1716 todo->setRelatedTo(QStringLiteral("3")); 1717 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1718 1719 QTest::newRow("nominal case") << item; 1720 1721 Akonadi::Item item2(16); 1722 QTest::newRow("parent invalid") << item2; 1723 } 1724 1725 void shouldRemoveItemParent() 1726 { 1727 // GIVEN 1728 QFETCH(Akonadi::Item, item); 1729 1730 // WHEN 1731 Akonadi::Serializer serializer; 1732 serializer.removeItemParent(item); 1733 1734 // THEN 1735 if (item.hasPayload<KCalendarCore::Todo::Ptr>()) 1736 QCOMPARE(item.payload<KCalendarCore::Todo::Ptr>()->relatedTo(), QString()); 1737 } 1738 1739 void shouldPromoteItemToProject_data() 1740 { 1741 QTest::addColumn<Akonadi::Item>("item"); 1742 1743 auto item = Akonadi::Item(15); 1744 auto todo = KCalendarCore::Todo::Ptr::create(); 1745 todo->setRelatedTo(QStringLiteral("3")); 1746 item.setPayload(todo); 1747 1748 QTest::newRow("nominal case") << item; 1749 QTest::newRow("invalid item") << Akonadi::Item(16); 1750 } 1751 1752 void shouldPromoteItemToProject() 1753 { 1754 // GIVEN 1755 QFETCH(Akonadi::Item, item); 1756 1757 // WHEN 1758 Akonadi::Serializer serializer; 1759 serializer.promoteItemToProject(item); 1760 1761 // THEN 1762 if (item.hasPayload<KCalendarCore::Todo::Ptr>()) { 1763 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 1764 QCOMPARE(todo->relatedTo(), QString()); 1765 QVERIFY(!todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject()).isEmpty()); 1766 } 1767 } 1768 1769 void shouldClearItem_data() 1770 { 1771 QTest::addColumn<Akonadi::Item*>("item"); 1772 1773 Akonadi::Item *itemWithContexts = new Akonadi::Item(15); 1774 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1775 // we can cheat and not really create contexts... 1776 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "one,two"); 1777 itemWithContexts->setPayload<KCalendarCore::Todo::Ptr>(todo); 1778 QTest::newRow("with_contexts") << itemWithContexts; 1779 1780 Akonadi::Item *itemWithNoContext = new Akonadi::Item(15); 1781 itemWithNoContext->setPayload<KCalendarCore::Todo::Ptr>(todo); 1782 QTest::newRow("no_context") << itemWithNoContext; 1783 } 1784 1785 void shouldClearItem() 1786 { 1787 // GIVEN 1788 QFETCH(Akonadi::Item*, item); 1789 1790 // WHEN 1791 Akonadi::Serializer serializer; 1792 serializer.clearItem(item); 1793 1794 // THEN 1795 auto todo = item->payload<KCalendarCore::Todo::Ptr>(); 1796 QVERIFY(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()).isEmpty()); 1797 delete item; 1798 } 1799 1800 void shouldCreateContextFromItem_data() 1801 { 1802 QTest::addColumn<QString>("name"); 1803 1804 QTest::newRow("nominal case") << "Context42"; 1805 QTest::newRow("empty name case") << ""; 1806 } 1807 1808 void shouldCreateContextFromItem() 1809 { 1810 // GIVEN 1811 1812 // Data... 1813 QFETCH(QString, name); 1814 1815 // ... stored in a todo... 1816 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1817 todo->setSummary(name); 1818 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext(), QStringLiteral("1")); 1819 QVERIFY(!todo->uid().isEmpty()); 1820 1821 // ... as payload of an item 1822 Akonadi::Item item(42); 1823 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1824 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1825 1826 // which has a parent collection 1827 Akonadi::Collection collection(43); 1828 item.setParentCollection(collection); 1829 1830 // WHEN 1831 Akonadi::Serializer serializer; 1832 Domain::Context::Ptr context = serializer.createContextFromItem(item); 1833 1834 // THEN 1835 QCOMPARE(context->name(), name); 1836 QCOMPARE(context->property("todoUid").toString(), todo->uid()); 1837 QCOMPARE(context->property("itemId").toLongLong(), item.id()); 1838 QCOMPARE(context->property("parentCollectionId").toLongLong(), collection.id()); 1839 } 1840 1841 void shouldNotCreateContextFromWrongItemType_data() 1842 { 1843 QTest::addColumn<bool>("isProject"); 1844 1845 QTest::newRow("project") << true; 1846 QTest::newRow("task") << false; 1847 } 1848 1849 void shouldNotCreateContextFromWrongItemType() 1850 { 1851 // GIVEN 1852 QFETCH(bool, isProject); 1853 1854 // A project todo 1855 KCalendarCore::Todo::Ptr originalTodo(new KCalendarCore::Todo); 1856 originalTodo->setSummary("summary"); 1857 if (isProject) 1858 originalTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1859 1860 // ... as payload of an item... 1861 Akonadi::Item originalItem; 1862 originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1863 originalItem.setPayload<KCalendarCore::Todo::Ptr>(originalTodo); 1864 1865 // WHEN 1866 Akonadi::Serializer serializer; 1867 Domain::Context::Ptr context = serializer.createContextFromItem(originalItem); 1868 1869 // THEN 1870 QVERIFY(!context); 1871 } 1872 1873 void shouldUpdateContextFromItem_data() 1874 { 1875 shouldCreateContextFromItem_data(); 1876 } 1877 1878 void shouldUpdateContextFromItem() 1879 { 1880 // GIVEN 1881 1882 // Data... 1883 QFETCH(QString, name); 1884 1885 // ... stored in a todo... 1886 KCalendarCore::Todo::Ptr todo(new KCalendarCore::Todo); 1887 todo->setSummary(name); 1888 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsContext(), QStringLiteral("1")); 1889 QVERIFY(!todo->uid().isEmpty()); 1890 1891 // ... as payload of an item 1892 Akonadi::Item item(42); 1893 item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1894 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 1895 1896 // WHEN 1897 Akonadi::Serializer serializer; 1898 Domain::Context::Ptr context(new Domain::Context); 1899 1900 serializer.updateContextFromItem(context, item); 1901 1902 // THEN 1903 QCOMPARE(context->name(), name); 1904 QCOMPARE(context->property("todoUid").toString(), todo->uid()); 1905 QCOMPARE(context->property("itemId").toLongLong(), item.id()); 1906 } 1907 1908 void shouldNotUpdateContextFromWrongItemType_data() 1909 { 1910 QTest::addColumn<bool>("isProject"); 1911 1912 QTest::newRow("project") << true; 1913 QTest::newRow("task") << false; 1914 } 1915 1916 void shouldNotUpdateContextFromWrongItemType() 1917 { 1918 // GIVEN 1919 QFETCH(bool, isProject); 1920 1921 // A context 1922 auto context = Domain::Context::Ptr::create(); 1923 context->setName("summary"); 1924 context->setProperty("todoUid", qint64(43)); 1925 1926 KCalendarCore::Todo::Ptr wrongTodo(new KCalendarCore::Todo); 1927 wrongTodo->setSummary("wrongSummary"); 1928 if (isProject) 1929 wrongTodo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyIsProject(), QStringLiteral("1")); 1930 1931 Akonadi::Item wrongItem; 1932 wrongItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); 1933 wrongItem.setPayload<KCalendarCore::Todo::Ptr>(wrongTodo); 1934 1935 // WHEN 1936 Akonadi::Serializer serializer; 1937 serializer.updateContextFromItem(context, wrongItem); 1938 1939 // THEN 1940 QCOMPARE(context->name(), "summary"); 1941 QCOMPARE(context->property("todoUid").toLongLong(), qint64(43)); 1942 } 1943 1944 void shouldVerifyIfAnItemIsAContextChild_data() 1945 { 1946 QTest::addColumn<Domain::Context::Ptr>("context"); 1947 QTest::addColumn<Akonadi::Item>("item"); 1948 QTest::addColumn<bool>("isChild"); 1949 1950 // Create a context 1951 auto context = Domain::Context::Ptr::create(); 1952 const QString contextUid = QStringLiteral("abc-123"); 1953 context->setProperty("todoUid", contextUid); 1954 1955 Akonadi::Item unrelatedItem; 1956 QTest::newRow("Unrelated item") << context << unrelatedItem << false; 1957 1958 Akonadi::Item relatedItem; 1959 auto todo = KCalendarCore::Todo::Ptr::create(); 1960 todo->setSummary("summary"); 1961 todo->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextUid); 1962 relatedItem.setPayload<KCalendarCore::Todo::Ptr>(todo); 1963 QTest::newRow("Related item") << context << relatedItem << true; 1964 1965 auto invalidContext = Domain::Context::Ptr::create(); 1966 QTest::newRow("Invalid context") << invalidContext << relatedItem << false; 1967 1968 Akonadi::Item invalidItem; 1969 QTest::newRow("Invalid Item") << context << invalidItem << false; 1970 } 1971 1972 void shouldVerifyIfAnItemIsAContextChild() 1973 { 1974 // GIVEN 1975 QFETCH(Domain::Context::Ptr, context); 1976 QFETCH(Akonadi::Item, item); 1977 QFETCH(bool, isChild); 1978 1979 // WHEN 1980 Akonadi::Serializer serializer; 1981 bool value = serializer.isContextChild(context, item); 1982 1983 // THEN 1984 QCOMPARE(value, isChild); 1985 } 1986 1987 void shouldCreateItemFromContext_data() 1988 { 1989 QTest::addColumn<QString>("name"); 1990 QTest::addColumn<qint64>("itemId"); 1991 QTest::addColumn<QString>("todoUid"); 1992 1993 const QString nameInternet = QStringLiteral("Internet"); 1994 const QString uid = QStringLiteral("uid-123"); 1995 1996 QTest::newRow("nominal_case") << nameInternet << qint64(42) << uid; 1997 QTest::newRow("no_item_id") << nameInternet<< qint64(-1) << uid; 1998 QTest::newRow("null_uid") << nameInternet << qint64(42) << QString(); 1999 QTest::newRow("no_name") << QString() << qint64(42) << uid; 2000 } 2001 2002 void shouldCreateItemFromContext() 2003 { 2004 // GIVEN 2005 QFETCH(QString, name); 2006 QFETCH(qint64, itemId); 2007 QFETCH(QString, todoUid); 2008 2009 // WHEN 2010 auto context = Domain::Context::Ptr::create(); 2011 context->setProperty("todoUid", todoUid); 2012 if (itemId > 0) 2013 context->setProperty("itemId", itemId); 2014 2015 context->setName(name); 2016 2017 Akonadi::Serializer serializer; 2018 Akonadi::Item item = serializer.createItemFromContext(context); 2019 auto todo = item.payload<KCalendarCore::Todo::Ptr>(); 2020 2021 // THEN 2022 QCOMPARE(todo->summary(), name); 2023 2024 if (!todoUid.isEmpty()) { 2025 QCOMPARE(todo->uid(), todoUid); 2026 } 2027 QCOMPARE(item.id(), itemId); 2028 } 2029 2030 void shouldTestIfItemRepresentsContext_data() 2031 { 2032 QTest::addColumn<QString>("contextUid"); 2033 QTest::addColumn<QString>("todoUid"); 2034 QTest::addColumn<bool>("expectedResult"); 2035 2036 QTest::newRow("yes") << "context-123" << "context-123" << true; 2037 QTest::newRow("no") << "context-123" << "another-context" << false; 2038 } 2039 2040 void shouldAddContextToTask_data() 2041 { 2042 QTest::addColumn<Domain::Context::Ptr>("context"); 2043 QTest::addColumn<Akonadi::Item>("item"); 2044 QTest::addColumn<QString>("expectedContextList"); 2045 2046 // Create a context 2047 auto context = Domain::Context::Ptr::create(); 2048 const QString contextUid = QStringLiteral("abc-123"); 2049 context->setProperty("todoUid", contextUid); 2050 2051 Akonadi::Item item; 2052 auto todo = KCalendarCore::Todo::Ptr::create(); 2053 todo->setSummary("summary"); 2054 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 2055 QTest::newRow("item_with_no_context") << context << item << contextUid; 2056 2057 Akonadi::Item item2; 2058 auto todo2 = KCalendarCore::Todo::Ptr::create(); 2059 todo2->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "another"); 2060 item2.setPayload<KCalendarCore::Todo::Ptr>(todo2); 2061 const QString bothContexts = QStringLiteral("another,") + contextUid; 2062 QTest::newRow("item_with_another_context") << context << item2 << bothContexts; 2063 2064 Akonadi::Item item3; 2065 auto todo3 = KCalendarCore::Todo::Ptr::create(); 2066 todo3->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), bothContexts); 2067 item3.setPayload<KCalendarCore::Todo::Ptr>(todo3); 2068 QTest::newRow("item_with_this_context_already") << context << item3 << bothContexts; 2069 } 2070 2071 void shouldAddContextToTask() 2072 { 2073 // GIVEN 2074 QFETCH(Domain::Context::Ptr, context); 2075 QFETCH(Akonadi::Item, item); 2076 QFETCH(QString, expectedContextList); 2077 2078 // WHEN 2079 Akonadi::Serializer serializer; 2080 serializer.addContextToTask(context, item); 2081 2082 // THEN 2083 KCalendarCore::Todo::Ptr todo = item.payload<KCalendarCore::Todo::Ptr>(); 2084 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), expectedContextList); 2085 } 2086 2087 void shouldRemoveContextFromTask_data() 2088 { 2089 QTest::addColumn<Domain::Context::Ptr>("context"); 2090 QTest::addColumn<Akonadi::Item>("item"); 2091 QTest::addColumn<QString>("expectedContextList"); 2092 2093 auto context = Domain::Context::Ptr::create(); 2094 const QString contextUid = QStringLiteral("abc-123"); 2095 context->setProperty("todoUid", contextUid); 2096 2097 Akonadi::Item item; 2098 auto todo = KCalendarCore::Todo::Ptr::create(); 2099 todo->setSummary("summary"); 2100 item.setPayload<KCalendarCore::Todo::Ptr>(todo); 2101 QTest::newRow("item_with_no_context") << context << item << QString(); 2102 2103 Akonadi::Item item2; 2104 auto todo2 = KCalendarCore::Todo::Ptr::create(); 2105 todo2->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), "another"); 2106 item2.setPayload<KCalendarCore::Todo::Ptr>(todo2); 2107 QTest::newRow("item_with_another_context") << context << item2 << QString("another"); 2108 2109 Akonadi::Item item3; 2110 auto todo3 = KCalendarCore::Todo::Ptr::create(); 2111 todo3->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), contextUid); 2112 item3.setPayload<KCalendarCore::Todo::Ptr>(todo3); 2113 QTest::newRow("item_with_this_context_already") << context << item3 << QString(); 2114 2115 Akonadi::Item item4; 2116 auto todo4 = KCalendarCore::Todo::Ptr::create(); 2117 const QString bothContexts = QStringLiteral("another,") + contextUid; 2118 todo4->setCustomProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList(), bothContexts); 2119 item4.setPayload<KCalendarCore::Todo::Ptr>(todo4); 2120 QTest::newRow("item_with_two_contexts") << context << item4 << QString("another"); 2121 } 2122 2123 void shouldRemoveContextFromTask() 2124 { 2125 // GIVEN 2126 QFETCH(Domain::Context::Ptr, context); 2127 QFETCH(Akonadi::Item, item); 2128 QFETCH(QString, expectedContextList); 2129 2130 // WHEN 2131 Akonadi::Serializer serializer; 2132 serializer.removeContextFromTask(context, item); 2133 2134 // THEN 2135 KCalendarCore::Todo::Ptr todo = item.payload<KCalendarCore::Todo::Ptr>(); 2136 QCOMPARE(todo->customProperty(Serializer::customPropertyAppName(), Serializer::customPropertyContextList()), expectedContextList); 2137 } 2138 2139 // Investigation into how to differentiate all-day events from events with time, 2140 // using QDateTime only. Doesn't seem to be possible. 2141 void noWayToHaveQDateTimeWithoutTime() 2142 { 2143 // GIVEN a QDateTime without time information 2144 QDateTime dateOnly(QDate(2016, 6, 12), QTime(-1, -1, -1)); 2145 // THEN we can't detect that there was no time information, i.e. all day event 2146 QVERIFY(dateOnly.time().isValid()); // I wish this was "!" 2147 QVERIFY(!dateOnly.time().isNull()); // got converted to midnight localtime by QDateTime 2148 // This doesn't help, QDateTime converts "null time" to midnight. 2149 dateOnly.setTime(QTime()); 2150 QVERIFY(dateOnly.time().isValid()); // same as above 2151 QVERIFY(!dateOnly.time().isNull()); // same as above 2152 2153 // GIVEN a QDateTime at midnight 2154 QDateTime atMidnight(QDate(2016, 6, 12), QTime(0, 0, 0)); 2155 // THEN we can detect that a time information was present 2156 QVERIFY(atMidnight.time().isValid()); 2157 QVERIFY(!atMidnight.time().isNull()); 2158 2159 #if 0 2160 // GIVEN a KDateTime without time information 2161 KDateTime kdOnly(QDate(2016, 6, 12)); 2162 // THEN we can detect that there was no time information, i.e. all day event 2163 QVERIFY(kdOnly.isDateOnly()); 2164 #endif 2165 } 2166 }; 2167 2168 ZANSHIN_TEST_MAIN(AkonadiSerializerTest) 2169 2170 #include "akonadiserializertest.moc"