diff --git a/src/akonadi/akonadiserializer.cpp b/src/akonadi/akonadiserializer.cpp index be41b181..ff6819a8 100644 --- a/src/akonadi/akonadiserializer.cpp +++ b/src/akonadi/akonadiserializer.cpp @@ -1,703 +1,689 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens Copyright 2014 Rémi Benoit This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "akonadiserializer.h" #include #include #include #include #include #include #include #include -#if KCALCORE_VERSION < QT_VERSION_CHECK(5, 6, 80) -#include -#endif #include #include "utils/mem_fn.h" #include "akonadi/akonadiapplicationselectedattribute.h" #include "akonadi/akonaditimestampattribute.h" using namespace Akonadi; Serializer::Serializer() { } Serializer::~Serializer() { } bool Serializer::representsCollection(SerializerInterface::QObjectPtr object, Collection collection) { return object->property("collectionId").toLongLong() == collection.id(); } bool Serializer::representsItem(QObjectPtr object, Item item) { return object->property("itemId").toLongLong() == item.id(); } bool Serializer::representsAkonadiTag(Domain::Tag::Ptr tag, Tag akonadiTag) const { return tag->property("tagId").toLongLong() == akonadiTag.id(); } QString Serializer::objectUid(SerializerInterface::QObjectPtr object) { return object->property("todoUid").toString(); } QString Serializer::itemUid(const Item &item) { if (isTaskItem(item)) { const auto todo = item.payload(); return todo->uid(); } else { return QString(); } } Domain::DataSource::Ptr Serializer::createDataSourceFromCollection(Collection collection, DataSourceNameScheme naming) { if (!collection.isValid()) return Domain::DataSource::Ptr(); auto dataSource = Domain::DataSource::Ptr::create(); updateDataSourceFromCollection(dataSource, collection, naming); return dataSource; } void Serializer::updateDataSourceFromCollection(Domain::DataSource::Ptr dataSource, Collection collection, DataSourceNameScheme naming) { if (!collection.isValid()) return; QString name = collection.displayName(); if (naming == FullPath) { auto parent = collection.parentCollection(); while (parent.isValid() && parent != Akonadi::Collection::root()) { name = parent.displayName() + " » " + name; parent = parent.parentCollection(); } } dataSource->setName(name); const auto mimeTypes = collection.contentMimeTypes(); auto types = Domain::DataSource::ContentTypes(); if (mimeTypes.contains(NoteUtils::noteMimeType())) types |= Domain::DataSource::Notes; if (mimeTypes.contains(KCalCore::Todo::todoMimeType())) types |= Domain::DataSource::Tasks; dataSource->setContentTypes(types); if (collection.hasAttribute()) { auto iconName = collection.attribute()->iconName(); dataSource->setIconName(iconName); } if (!collection.hasAttribute()) { dataSource->setSelected(true); } else { auto isSelected = collection.attribute()->isSelected(); dataSource->setSelected(isSelected); } dataSource->setProperty("collectionId", collection.id()); } Collection Serializer::createCollectionFromDataSource(Domain::DataSource::Ptr dataSource) { const auto id = dataSource->property("collectionId").value(); auto collection = Collection(id); collection.attribute(Akonadi::Collection::AddIfMissing); auto selectedAttribute = collection.attribute(Akonadi::Collection::AddIfMissing); selectedAttribute->setSelected(dataSource->isSelected()); return collection; } bool Serializer::isSelectedCollection(Collection collection) { if (!isNoteCollection(collection) && !isTaskCollection(collection)) return false; if (!collection.hasAttribute()) return true; return collection.attribute()->isSelected(); } bool Akonadi::Serializer::isNoteCollection(Akonadi::Collection collection) { return collection.contentMimeTypes().contains(NoteUtils::noteMimeType()); } bool Akonadi::Serializer::isTaskCollection(Akonadi::Collection collection) { return collection.contentMimeTypes().contains(KCalCore::Todo::todoMimeType()); } bool Serializer::isTaskItem(Item item) { if (!item.hasPayload()) return false; auto todo = item.payload(); return todo->customProperty("Zanshin", "Project").isEmpty(); } Domain::Task::Ptr Serializer::createTaskFromItem(Item item) { if (!isTaskItem(item)) return Domain::Task::Ptr(); auto task = Domain::Task::Ptr::create(); updateTaskFromItem(task, item); return task; } void Serializer::updateTaskFromItem(Domain::Task::Ptr task, Item item) { if (!isTaskItem(item)) return; auto todo = item.payload(); task->setTitle(todo->summary()); task->setText(todo->description()); task->setDone(todo->isCompleted()); -#if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 6, 80) task->setDoneDate(todo->completed().toLocalTime().date()); task->setStartDate(todo->dtStart().toLocalTime().date()); task->setDueDate(todo->dtDue().toLocalTime().date()); -#else - task->setDoneDate(todo->completed().dateTime().toLocalTime().date()); - task->setStartDate(todo->dtStart().dateTime().toLocalTime().date()); - task->setDueDate(todo->dtDue().dateTime().toLocalTime().date()); -#endif task->setProperty("itemId", item.id()); task->setProperty("parentCollectionId", item.parentCollection().id()); task->setProperty("todoUid", todo->uid()); task->setProperty("relatedUid", todo->relatedTo()); task->setRunning(todo->customProperty("Zanshin", "Running") == QLatin1String("1")); switch (todo->recurrence()->recurrenceType()) { case KCalCore::Recurrence::rDaily: task->setRecurrence(Domain::Task::RecursDaily); break; case KCalCore::Recurrence::rWeekly: task->setRecurrence(Domain::Task::RecursWeekly); break; case KCalCore::Recurrence::rMonthlyDay: task->setRecurrence(Domain::Task::RecursMonthly); break; default: // Other cases are not supported for now and as such just ignored break; } QMimeDatabase mimeDb; const auto attachmentsInput = todo->attachments(); Domain::Task::Attachments attachments; attachments.reserve(attachmentsInput.size()); std::transform(attachmentsInput.cbegin(), attachmentsInput.cend(), std::back_inserter(attachments), [&mimeDb] (const KCalCore::Attachment::Ptr &attach) { Domain::Task::Attachment attachment; if (attach->isUri()) attachment.setUri(QUrl(attach->uri())); else attachment.setData(attach->decodedData()); attachment.setLabel(attach->label()); attachment.setMimeType(attach->mimeType()); attachment.setIconName(mimeDb.mimeTypeForName(attach->mimeType()).iconName()); return attachment; }); task->setAttachments(attachments); if (todo->attendeeCount() > 0) { const auto attendees = todo->attendees(); const auto delegate = std::find_if(attendees.begin(), attendees.end(), [] (const KCalCore::Attendee::Ptr &attendee) { return attendee->status() == KCalCore::Attendee::Accepted; }); if (delegate != attendees.end()) { task->setDelegate(Domain::Task::Delegate((*delegate)->name(), (*delegate)->email())); } } } bool Serializer::isTaskChild(Domain::Task::Ptr task, Akonadi::Item item) { if (!isTaskItem(item)) return false; auto todo = item.payload(); if (todo->relatedTo() == task->property("todoUid")) return true; return false; } -#if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 6, 80) -#define KDateTime QDateTime -#endif - - Akonadi::Item Serializer::createItemFromTask(Domain::Task::Ptr task) { auto todo = KCalCore::Todo::Ptr::create(); todo->setSummary(task->title()); todo->setDescription(task->text()); // We only support all-day todos, so ignore timezone information and possible effect from timezone on dates // KCalCore reads "DUE;VALUE=DATE:20171130" as QDateTime(QDate(2017, 11, 30), QTime(), Qt::LocalTime), for lack of timezone information // so we should never call toUtc() on that, it would mess up the date. // If one day we want to support time information, we need to add a task->isAllDay()/setAllDay(). todo->setDtStart(QDateTime(task->startDate())); todo->setDtDue(QDateTime(task->dueDate())); todo->setAllDay(true); if (task->property("todoUid").isValid()) { todo->setUid(task->property("todoUid").toString()); } if (task->property("relatedUid").isValid()) { todo->setRelatedTo(task->property("relatedUid").toString()); } switch (task->recurrence()) { case Domain::Task::NoRecurrence: break; case Domain::Task::RecursDaily: todo->recurrence()->setDaily(1); break; case Domain::Task::RecursWeekly: todo->recurrence()->setWeekly(1); break; case Domain::Task::RecursMonthly: todo->recurrence()->setMonthly(1); break; } for (const auto &attachment : task->attachments()) { KCalCore::Attachment::Ptr attach(new KCalCore::Attachment(QByteArray())); if (attachment.isUri()) attach->setUri(attachment.uri().toString()); else attach->setDecodedData(attachment.data()); attach->setMimeType(attachment.mimeType()); attach->setLabel(attachment.label()); todo->addAttachment(attach); } if (task->delegate().isValid()) { KCalCore::Attendee::Ptr attendee(new KCalCore::Attendee(task->delegate().name(), task->delegate().email(), true, KCalCore::Attendee::Accepted)); todo->addAttendee(attendee); } if (task->isRunning()) { todo->setCustomProperty("Zanshin", "Running", "1"); } else { todo->removeCustomProperty("Zanshin", "Running"); } // Needs to be done after all other dates are positioned // since this applies the recurrence logic if (task->isDone()) todo->setCompleted(QDateTime(task->doneDate(), QTime(), Qt::UTC)); else todo->setCompleted(false); Akonadi::Item item; if (task->property("itemId").isValid()) { item.setId(task->property("itemId").value()); } if (task->property("parentCollectionId").isValid()) { auto parentId = task->property("parentCollectionId").value(); item.setParentCollection(Akonadi::Collection(parentId)); } item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); return item; } QString Serializer::relatedUidFromItem(Akonadi::Item item) { if (isTaskItem(item)) { const auto todo = item.payload(); return todo->relatedTo(); } else if (isNoteItem(item)) { const auto message = item.payload(); const auto relatedHeader = message->headerByType("X-Zanshin-RelatedProjectUid"); return relatedHeader ? relatedHeader->asUnicodeString() : QString(); } else { return QString(); } } void Serializer::updateItemParent(Akonadi::Item item, Domain::Task::Ptr parent) { if (!isTaskItem(item)) return; auto todo = item.payload(); todo->setRelatedTo(parent->property("todoUid").toString()); } void Serializer::updateItemProject(Item item, Domain::Project::Ptr project) { if (isTaskItem(item)) { auto todo = item.payload(); todo->setRelatedTo(project->property("todoUid").toString()); } else if (isNoteItem(item)) { auto note = item.payload(); note->removeHeader("X-Zanshin-RelatedProjectUid"); const QByteArray parentUid = project->property("todoUid").toString().toUtf8(); if (!parentUid.isEmpty()) { auto relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString(parentUid); note->appendHeader(relatedHeader); } note->assemble(); } } void Serializer::removeItemParent(Akonadi::Item item) { if (!isTaskItem(item)) return; auto todo = item.payload(); todo->setRelatedTo(QString()); } void Serializer::promoteItemToProject(Akonadi::Item item) { if (!isTaskItem(item)) return; auto todo = item.payload(); todo->setRelatedTo(QString()); todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); } void Serializer::clearItem(Akonadi::Item *item) { Q_ASSERT(item); if (!isTaskItem(*item)) return; // NOTE : Currently not working, when akonadistorage test will make it pass, we will use it // item->clearTags(); foreach (const Tag& tag, item->tags()) item->clearTag(tag); } Akonadi::Item::List Serializer::filterDescendantItems(const Akonadi::Item::List &potentialChildren, const Akonadi::Item &ancestorItem) { if (potentialChildren.isEmpty()) return Akonadi::Item::List(); Akonadi::Item::List itemsToProcess = potentialChildren; Q_ASSERT(ancestorItem.isValid() && ancestorItem.hasPayload()); KCalCore::Todo::Ptr todo = ancestorItem.payload(); const auto bound = std::partition(itemsToProcess.begin(), itemsToProcess.end(), [ancestorItem, todo](Akonadi::Item currentItem) { return (!currentItem.hasPayload() || currentItem == ancestorItem || currentItem.payload()->relatedTo() != todo->uid()); }); Akonadi::Item::List itemsRemoved; itemsRemoved.reserve(std::distance(itemsToProcess.begin(), bound)); std::copy(itemsToProcess.begin(), bound, std::back_inserter(itemsRemoved)); itemsToProcess.erase(itemsToProcess.begin(), bound); auto result = std::accumulate(itemsToProcess.begin(), itemsToProcess.end(), Akonadi::Item::List(), [this, itemsRemoved](Akonadi::Item::List result, Akonadi::Item currentItem) { result << currentItem; return result += filterDescendantItems(itemsRemoved, currentItem); }); return result; } bool Serializer::isNoteItem(Item item) { return item.hasPayload(); } Domain::Note::Ptr Serializer::createNoteFromItem(Akonadi::Item item) { if (!isNoteItem(item)) return Domain::Note::Ptr(); Domain::Note::Ptr note = Domain::Note::Ptr::create(); updateNoteFromItem(note, item); return note; } void Serializer::updateNoteFromItem(Domain::Note::Ptr note, Item item) { if (!isNoteItem(item)) return; auto message = item.payload(); note->setTitle(message->subject(true)->asUnicodeString()); note->setText(message->mainBodyPart()->decodedText()); note->setProperty("itemId", item.id()); if (auto relatedHeader = message->headerByType("X-Zanshin-RelatedProjectUid")) { note->setProperty("relatedUid", relatedHeader->asUnicodeString()); } else { note->setProperty("relatedUid", QVariant()); } } Item Serializer::createItemFromNote(Domain::Note::Ptr note) { NoteUtils::NoteMessageWrapper builder; builder.setTitle(note->title()); builder.setText(note->text() + '\n'); // Adding an extra '\n' because KMime always removes it... KMime::Message::Ptr message = builder.message(); if (!note->property("relatedUid").toString().isEmpty()) { auto relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString(note->property("relatedUid").toString().toUtf8()); message->appendHeader(relatedHeader); } Akonadi::Item item; if (note->property("itemId").isValid()) { item.setId(note->property("itemId").value()); } item.setMimeType(Akonadi::NoteUtils::noteMimeType()); item.setPayload(message); return item; } bool Serializer::isProjectItem(Item item) { if (!item.hasPayload()) return false; return !isTaskItem(item); } Domain::Project::Ptr Serializer::createProjectFromItem(Item item) { if (!isProjectItem(item)) return Domain::Project::Ptr(); auto project = Domain::Project::Ptr::create(); updateProjectFromItem(project, item); return project; } void Serializer::updateProjectFromItem(Domain::Project::Ptr project, Item item) { if (!isProjectItem(item)) return; auto todo = item.payload(); project->setName(todo->summary()); project->setProperty("itemId", item.id()); project->setProperty("parentCollectionId", item.parentCollection().id()); project->setProperty("todoUid", todo->uid()); } Item Serializer::createItemFromProject(Domain::Project::Ptr project) { auto todo = KCalCore::Todo::Ptr::create(); todo->setSummary(project->name()); todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); if (project->property("todoUid").isValid()) { todo->setUid(project->property("todoUid").toString()); } Akonadi::Item item; if (project->property("itemId").isValid()) { item.setId(project->property("itemId").value()); } if (project->property("parentCollectionId").isValid()) { auto parentId = project->property("parentCollectionId").value(); item.setParentCollection(Akonadi::Collection(parentId)); } item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); return item; } bool Serializer::isProjectChild(Domain::Project::Ptr project, Item item) { const QString todoUid = project->property("todoUid").toString(); const QString relatedUid = relatedUidFromItem(item); return !todoUid.isEmpty() && !relatedUid.isEmpty() && todoUid == relatedUid; } Domain::Context::Ptr Serializer::createContextFromTag(Akonadi::Tag tag) { if (!isContext(tag)) return Domain::Context::Ptr(); auto context = Domain::Context::Ptr::create(); updateContextFromTag(context, tag); return context; } Akonadi::Tag Serializer::createTagFromContext(Domain::Context::Ptr context) { auto tag = Akonadi::Tag(); tag.setName(context->name()); tag.setType(Akonadi::SerializerInterface::contextTagType()); tag.setGid(QByteArray(context->name().toLatin1())); if (context->property("tagId").isValid()) tag.setId(context->property("tagId").value()); return tag; } void Serializer::updateContextFromTag(Domain::Context::Ptr context, Akonadi::Tag tag) { if (!isContext(tag)) return; context->setProperty("tagId", tag.id()); context->setName(tag.name()); } bool Serializer::hasContextTags(Item item) const { using namespace std::placeholders; Tag::List tags = item.tags(); return std::any_of(tags.constBegin(), tags.constEnd(), std::bind(Utils::mem_fn(&Serializer::isContext), this, _1)); } bool Serializer::hasAkonadiTags(Item item) const { using namespace std::placeholders; Tag::List tags = item.tags(); return std::any_of(tags.constBegin(), tags.constEnd(), std::bind(Utils::mem_fn(&Serializer::isAkonadiTag), this, _1)); } bool Serializer::isContext(const Akonadi::Tag &tag) const { return (tag.type() == Akonadi::SerializerInterface::contextTagType()); } bool Serializer::isAkonadiTag(const Tag &tag) const { return tag.type() == Akonadi::Tag::PLAIN; } bool Serializer::isContextTag(const Domain::Context::Ptr &context, const Akonadi::Tag &tag) const { return (context->property("tagId").value() == tag.id()); } bool Serializer::isContextChild(Domain::Context::Ptr context, Item item) const { if (!context->property("tagId").isValid()) return false; auto tagId = context->property("tagId").value(); Akonadi::Tag tag(tagId); return item.hasTag(tag); } Domain::Tag::Ptr Serializer::createTagFromAkonadiTag(Akonadi::Tag akonadiTag) { if (!isAkonadiTag(akonadiTag)) return Domain::Tag::Ptr(); auto tag = Domain::Tag::Ptr::create(); updateTagFromAkonadiTag(tag, akonadiTag); return tag; } void Serializer::updateTagFromAkonadiTag(Domain::Tag::Ptr tag, Akonadi::Tag akonadiTag) { if (!isAkonadiTag(akonadiTag)) return; tag->setProperty("tagId", akonadiTag.id()); tag->setName(akonadiTag.name()); } Akonadi::Tag Serializer::createAkonadiTagFromTag(Domain::Tag::Ptr tag) { auto akonadiTag = Akonadi::Tag(); akonadiTag.setName(tag->name()); akonadiTag.setType(Akonadi::Tag::PLAIN); akonadiTag.setGid(QByteArray(tag->name().toLatin1())); const auto tagProperty = tag->property("tagId"); if (tagProperty.isValid()) akonadiTag.setId(tagProperty.value()); return akonadiTag; } bool Serializer::isTagChild(Domain::Tag::Ptr tag, Akonadi::Item item) { if (!tag->property("tagId").isValid()) return false; auto tagId = tag->property("tagId").value(); Akonadi::Tag akonadiTag(tagId); return item.hasTag(akonadiTag); } diff --git a/src/presentation/artifactfilterproxymodel.cpp b/src/presentation/artifactfilterproxymodel.cpp index c6b6a054..c5641b50 100644 --- a/src/presentation/artifactfilterproxymodel.cpp +++ b/src/presentation/artifactfilterproxymodel.cpp @@ -1,140 +1,140 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "artifactfilterproxymodel.h" #include #include "domain/artifact.h" #include "domain/task.h" #include "utils/datetime.h" #include "presentation/querytreemodelbase.h" using namespace Presentation; ArtifactFilterProxyModel::ArtifactFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_sortType(TitleSort), m_showFuture(false) { setDynamicSortFilter(true); setSortCaseSensitivity(Qt::CaseInsensitive); setSortOrder(Qt::AscendingOrder); } ArtifactFilterProxyModel::SortType ArtifactFilterProxyModel::sortType() const { return m_sortType; } void ArtifactFilterProxyModel::setSortType(ArtifactFilterProxyModel::SortType type) { m_sortType = type; invalidate(); } void ArtifactFilterProxyModel::setSortOrder(Qt::SortOrder order) { sort(0, order); } bool ArtifactFilterProxyModel::showFutureTasks() const { return m_showFuture; } void ArtifactFilterProxyModel::setShowFutureTasks(bool show) { if (m_showFuture == show) return; m_showFuture = show; invalidate(); } static bool isFutureTask(const Domain::Artifact::Ptr &artifact) { auto task = artifact.objectCast(); if (!task) return false; if (!task->startDate().isValid()) return false; return task->startDate() > Utils::DateTime::currentDate(); } bool ArtifactFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); const auto artifact = index.data(QueryTreeModelBase::ObjectRole).value(); if (artifact) { QRegExp regexp = filterRegExp(); regexp.setCaseSensitivity(Qt::CaseInsensitive); if (artifact->title().contains(regexp) || artifact->text().contains(regexp)) { return m_showFuture || !isFutureTask(artifact); } } for (int childRow = 0; childRow < sourceModel()->rowCount(index); childRow++) { if (filterAcceptsRow(childRow, index)) return true; } return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } -static QDate validDt(const QDate &date = QDate()) +static QDate validDate(const QDate &date = QDate()) { if (date.isValid()) return date; - return QDate(10000, 12, 31); + return QDate(80000, 12, 31); } bool ArtifactFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { if (m_sortType != DateSort) return QSortFilterProxyModel::lessThan(left, right); const auto leftArtifact = left.data(QueryTreeModelBase::ObjectRole).value(); const auto rightArtifact = right.data(QueryTreeModelBase::ObjectRole).value(); const auto leftTask = leftArtifact.objectCast(); const auto rightTask = rightArtifact.objectCast(); // The addDays(1) is so that we sort non-tasks (e.g. notes) at the end - const QDate leftDue = leftTask ? validDt(leftTask->dueDate()) : validDt().addDays(1); - const QDate rightDue = rightTask ? validDt(rightTask->dueDate()) : validDt().addDays(1); + const QDate leftDue = leftTask ? validDate(leftTask->dueDate()) : validDate().addDays(1); + const QDate rightDue = rightTask ? validDate(rightTask->dueDate()) : validDate().addDays(1); - const QDate leftStart = leftTask ? validDt(leftTask->startDate()) : validDt().addDays(1); - const QDate rightStart = rightTask ? validDt(rightTask->startDate()) : validDt().addDays(1); + const QDate leftStart = leftTask ? validDate(leftTask->startDate()) : validDate().addDays(1); + const QDate rightStart = rightTask ? validDate(rightTask->startDate()) : validDate().addDays(1); return leftDue < rightDue || leftStart < rightStart; } diff --git a/src/utils/datetime.cpp b/src/utils/datetime.cpp index 37136967..02394b70 100644 --- a/src/utils/datetime.cpp +++ b/src/utils/datetime.cpp @@ -1,44 +1,36 @@ /* This file is part of Zanshin Copyright 2015 Theo Vaucher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "datetime.h" #include using namespace Utils; -QDateTime DateTime::currentDateTime() -{ - QByteArray overrideDatetime = qgetenv("ZANSHIN_OVERRIDE_DATETIME"); - QDateTime customDateTime = QDateTime::fromString(QString::fromLocal8Bit(overrideDatetime), Qt::ISODate); - - return customDateTime.isValid() ? customDateTime : QDateTime::currentDateTime(); -} - QDate DateTime::currentDate() { QByteArray overrideDate = qgetenv("ZANSHIN_OVERRIDE_DATE"); QDate customDate = QDate::fromString(QString::fromLocal8Bit(overrideDate), Qt::ISODate); return customDate.isValid() ? customDate : QDate::currentDate(); } diff --git a/src/utils/datetime.h b/src/utils/datetime.h index 0f2be749..93f01618 100644 --- a/src/utils/datetime.h +++ b/src/utils/datetime.h @@ -1,40 +1,39 @@ /* This file is part of Zanshin Copyright 2015 Theo Vaucher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UTILS_DATETIME #define UTILS_DATETIME class QDateTime; class QDate; namespace Utils { namespace DateTime { - QDateTime currentDateTime(); QDate currentDate(); } } #endif // UTILS_DATETIME diff --git a/tests/testlib/gentodo.cpp b/tests/testlib/gentodo.cpp index 55f32f4b..10a7c6f5 100644 --- a/tests/testlib/gentodo.cpp +++ b/tests/testlib/gentodo.cpp @@ -1,158 +1,157 @@ /* This file is part of Zanshin Copyright 2015 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gentodo.h" #include #include -#include using namespace Testlib; GenTodo::GenTodo(const Akonadi::Item &item) : m_item(item) { m_item.setMimeType(KCalCore::Todo::todoMimeType()); if (!m_item.hasPayload()) m_item.setPayload(KCalCore::Todo::Ptr::create()); } Testlib::GenTodo::operator Akonadi::Item() { return m_item; } GenTodo &GenTodo::withId(Akonadi::Item::Id id) { m_item.setId(id); return *this; } GenTodo &GenTodo::withParent(Akonadi::Collection::Id id) { m_item.setParentCollection(Akonadi::Collection(id)); return *this; } GenTodo &GenTodo::withTags(const QList &ids) { auto tags = Akonadi::Tag::List(); std::transform(ids.constBegin(), ids.constEnd(), std::back_inserter(tags), [] (Akonadi::Tag::Id id) { return Akonadi::Tag(id); }); m_item.setTags(tags); return *this; } GenTodo &GenTodo::asProject(bool value) { auto todo = m_item.payload(); if (value) todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); else todo->removeCustomProperty("Zanshin", "Project"); return *this; } GenTodo &GenTodo::withUid(const QString &uid) { m_item.payload()->setUid(uid); return *this; } GenTodo &GenTodo::withParentUid(const QString &uid) { m_item.payload()->setRelatedTo(uid); return *this; } GenTodo &GenTodo::withTitle(const QString &title) { m_item.payload()->setSummary(title); return *this; } GenTodo &GenTodo::withText(const QString &text) { m_item.payload()->setDescription(text); return *this; } GenTodo &GenTodo::done(bool value) { m_item.payload()->setCompleted(value); return *this; } GenTodo &GenTodo::withDoneDate(const QString &date) { m_item.payload()->setCompleted(QDateTime(QDate::fromString(date, Qt::ISODate))); return *this; } GenTodo &GenTodo::withDoneDate(const QDate &date) { m_item.payload()->setCompleted(QDateTime(date)); return *this; } GenTodo &GenTodo::withStartDate(const QString &date) { m_item.payload()->setDtStart(QDateTime(QDate::fromString(date, Qt::ISODate))); return *this; } GenTodo &GenTodo::withStartDate(const QDate &date) { m_item.payload()->setDtStart(QDateTime(date)); return *this; } GenTodo &GenTodo::withDueDate(const QString &date) { m_item.payload()->setDtDue(QDateTime(QDate::fromString(date, Qt::ISODate))); return *this; } GenTodo &GenTodo::withDueDate(const QDate &date) { m_item.payload()->setDtDue(QDateTime(date)); return *this; } GenTodo &GenTodo::withDelegate(const QString &name, const QString &email) { withNoDelegate(); KCalCore::Attendee::Ptr attendee(new KCalCore::Attendee(name, email, true, KCalCore::Attendee::Delegated)); m_item.payload()->addAttendee(attendee); return *this; } GenTodo &GenTodo::withNoDelegate() { m_item.payload()->clearAttendees(); return *this; } diff --git a/tests/units/akonadi/akonadiserializertest.cpp b/tests/units/akonadi/akonadiserializertest.cpp index 88170c68..45e4f44b 100644 --- a/tests/units/akonadi/akonadiserializertest.cpp +++ b/tests/units/akonadi/akonadiserializertest.cpp @@ -1,2682 +1,2667 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens Copyright 2014 Rémi Benoit This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "akonadi/akonadiserializer.h" #include "akonadi/akonadiapplicationselectedattribute.h" #include "akonadi/akonaditimestampattribute.h" #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(Akonadi::Item*) #if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 6, 80) #define KDateTime QDateTime #endif static void setTodoDates(KCalCore::Todo::Ptr todo, const QDate &start, const QDate &due) { todo->setDtStart(QDateTime(start)); todo->setDtDue(QDateTime(due)); } class AkonadiSerializerTest : public QObject { Q_OBJECT private slots: void shouldKnowWhenAnObjectRepresentsACollection() { // GIVEN Akonadi::Serializer serializer; auto object = Akonadi::Serializer::QObjectPtr::create(); Akonadi::Collection collection(42); // WHEN // Nothing yet // THEN QVERIFY(!serializer.representsCollection(object, collection)); // WHEN object->setProperty("collectionId", 42); // THEN QVERIFY(serializer.representsCollection(object, collection)); // WHEN object->setProperty("collectionId", 43); // THEN QVERIFY(!serializer.representsCollection(object, collection)); } void shouldKnowWhenAnObjectRepresentsAnItem() { // GIVEN Akonadi::Serializer serializer; auto object = Akonadi::Serializer::QObjectPtr::create(); Akonadi::Item item(42); // WHEN // Nothing yet // THEN QVERIFY(!serializer.representsItem(object, item)); // WHEN object->setProperty("itemId", 42); // THEN QVERIFY(serializer.representsItem(object, item)); // WHEN object->setProperty("itemId", 43); // THEN QVERIFY(!serializer.representsItem(object, item)); } void shouldKnowWhenAnAkonadiTagRepresentsATag() { // GIVEN Akonadi::Serializer serializer; Akonadi::Tag akondiTag(42); auto tag = Domain::Tag::Ptr::create(); // WHEN // Nothing yet // THEN QVERIFY(!serializer.representsAkonadiTag(tag, akondiTag)); // WHEN tag->setProperty("tagId", 42); // THEN QVERIFY(serializer.representsAkonadiTag(tag, akondiTag)); // WHEN tag->setProperty("tagId", 43); // THEN QVERIFY(!serializer.representsAkonadiTag(tag, akondiTag)); } void shouldKnowObjectUid() { // GIVEN Akonadi::Serializer serializer; auto object = Akonadi::Serializer::QObjectPtr::create(); // WHEN object->setProperty("todoUid", "my-uid"); // THEN QCOMPARE(serializer.objectUid(object), QStringLiteral("my-uid")); } void shouldKnowTaskItemUid_data() { QTest::addColumn("item"); QTest::addColumn("expectedUid"); Akonadi::Item item1; KCalCore::Todo::Ptr todo1(new KCalCore::Todo); todo1->setUid(QString()); item1.setPayload(todo1); Akonadi::Item item2; KCalCore::Todo::Ptr todo2(new KCalCore::Todo); todo2->setUid(QStringLiteral("1")); item2.setPayload(todo2); Akonadi::Item item3; KMime::Message::Ptr message(new KMime::Message); message->subject(true)->fromUnicodeString(QStringLiteral("foo"), "utf-8"); message->mainBodyPart()->fromUnicodeString(QStringLiteral("bar")); item3.setMimeType(Akonadi::NoteUtils::noteMimeType()); item3.setPayload(message); QTest::newRow("task without uid") << item1 << QString(); QTest::newRow("task with uid") << item2 << "1"; QTest::newRow("note") << item3 << QString(); } void shouldKnowTaskItemUid() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(QString, expectedUid); // WHEN Akonadi::Serializer serializer; QString uid = serializer.itemUid(item); // THEN QCOMPARE(uid, expectedUid); } void shouldCreateDataSourceFromCollection_data() { QTest::addColumn("name"); QTest::addColumn("iconName"); QTest::addColumn("mimeTypes"); QTest::addColumn("hasSelectedAttribute"); QTest::addColumn("isSelected"); const auto noteMimeTypes = QStringList() << QStringLiteral("text/x-vnd.akonadi.note"); const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar"); const auto allMimeTypes = noteMimeTypes + taskMimeTypes + bogusMimeTypes; QTest::newRow("nominal case") << "name" << "icon" << allMimeTypes << true << false; QTest::newRow("only notes") << "name" << "icon" << noteMimeTypes << true << false; QTest::newRow("only tasks") << "name" << "icon" << taskMimeTypes << true << false; QTest::newRow("only bogus") << "name" << "icon" << bogusMimeTypes << true << false; QTest::newRow("no selected attribute") << "name" << "icon" << allMimeTypes << false << false; QTest::newRow("selected attribute (false)") << "name" << "icon" << allMimeTypes << true << false; QTest::newRow("selected attribute (true)") << "name" << "icon" << allMimeTypes << true << true; QTest::newRow("empty case") << QString() << QString() << QStringList() << false << false; } void shouldCreateDataSourceFromCollection() { // GIVEN // Data... QFETCH(QString, name); QFETCH(QString, iconName); QFETCH(QStringList, mimeTypes); QFETCH(bool, hasSelectedAttribute); QFETCH(bool, isSelected); Domain::DataSource::ContentTypes expectedContentTypes; if (mimeTypes.contains(QStringLiteral("text/x-vnd.akonadi.note"))) { expectedContentTypes |= Domain::DataSource::Notes; } if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) { expectedContentTypes |= Domain::DataSource::Tasks; } // ... stored in a collection Akonadi::Collection collection(42); collection.setContentMimeTypes(mimeTypes); collection.setName(name); auto displayAttribute = new Akonadi::EntityDisplayAttribute; displayAttribute->setIconName(iconName); collection.addAttribute(displayAttribute); if (hasSelectedAttribute) { auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute; selectedAttribute->setSelected(isSelected); collection.addAttribute(selectedAttribute); } // WHEN Akonadi::Serializer serializer; auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); // THEN QCOMPARE(dataSource->name(), name); QCOMPARE(dataSource->iconName(), iconName); QCOMPARE(dataSource->contentTypes(), expectedContentTypes); QCOMPARE(dataSource->isSelected(), !hasSelectedAttribute || isSelected); QCOMPARE(dataSource->property("collectionId").value(), collection.id()); } void shouldCreateNullDataSourceFromInvalidCollection() { // GIVEN Akonadi::Collection collection; // WHEN Akonadi::Serializer serializer; auto dataSource = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); // THEN QVERIFY(dataSource.isNull()); } void shouldUpdateDataSourceFromCollection_data() { QTest::addColumn("updatedName"); QTest::newRow("no change") << "name"; QTest::newRow("changed") << "new name"; } void shouldUpdateDataSourceFromCollection() { // GIVEN // A collection... Akonadi::Collection originalCollection(42); originalCollection.setName(QStringLiteral("name")); // ... deserialized as a data source Akonadi::Serializer serializer; auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName); // WHEN // Data... QFETCH(QString, updatedName); // ... in a new collection Akonadi::Collection updatedCollection(42); updatedCollection.setName(updatedName); serializer.updateDataSourceFromCollection(dataSource, updatedCollection, Akonadi::SerializerInterface::BaseName); // THEN QCOMPARE(dataSource->name(), updatedName); } void shouldNotUpdateDataSourceFromInvalidCollection() { // GIVEN // Data... const QString name = QStringLiteral("name"); // ... stored in a collection... Akonadi::Collection originalCollection(42); originalCollection.setName(name); // ... deserialized as a data source Akonadi::Serializer serializer; auto dataSource = serializer.createDataSourceFromCollection(originalCollection, Akonadi::SerializerInterface::BaseName); // WHEN Akonadi::Collection invalidCollection; invalidCollection.setName(QStringLiteral("foo")); serializer.updateDataSourceFromCollection(dataSource, invalidCollection, Akonadi::SerializerInterface::BaseName); // THEN QCOMPARE(dataSource->name(), name); } void shouldNameDataSourceFromCollectionPathIfRequested() { // GIVEN // Data... const QString name = QStringLiteral("name"); const QString parentName = QStringLiteral("parent"); // ... stored in a collection with a parent Akonadi::Collection collection(42); collection.setName(name); Akonadi::Collection parentCollection(41); parentCollection.setName(QStringLiteral("Foo")); auto attribute = new Akonadi::EntityDisplayAttribute; attribute->setDisplayName(parentName); parentCollection.addAttribute(attribute); collection.setParentCollection(parentCollection); // WHEN Akonadi::Serializer serializer; auto dataSource1 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath); auto dataSource2 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); // Give it another try with the root parentCollection.setParentCollection(Akonadi::Collection::root()); collection.setParentCollection(parentCollection); auto dataSource3 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::FullPath); auto dataSource4 = serializer.createDataSourceFromCollection(collection, Akonadi::SerializerInterface::BaseName); // THEN QCOMPARE(dataSource1->name(), QString(parentName + " » " + name)); QCOMPARE(dataSource2->name(), name); QCOMPARE(dataSource3->name(), QString(parentName + " » " + name)); QCOMPARE(dataSource4->name(), name); } void shouldCreateCollectionFromDataSource_data() { QTest::addColumn("name"); QTest::addColumn("iconName"); QTest::addColumn("contentTypes"); QTest::addColumn("isSelected"); const auto noType = Domain::DataSource::ContentTypes(Domain::DataSource::NoContent); const auto taskType = Domain::DataSource::ContentTypes(Domain::DataSource::Tasks); const auto noteType = Domain::DataSource::ContentTypes(Domain::DataSource::Notes); const auto allTypes = taskType | noteType; QTest::newRow("nominal case") << "name" << "icon-name" << allTypes << true; QTest::newRow("only notes") << "name" << "icon-name" << noteType << true; QTest::newRow("only tasks") << "name" << "icon-name" << taskType << true; QTest::newRow("only nothing ;)") << "name" << "icon-name" << noType << true; QTest::newRow("not selected") << "name" << "icon-name" << allTypes << false; QTest::newRow("selected") << "name" << "icon-name" << allTypes << true; QTest::newRow("empty case") << QString() << QString() << noType << true; } void shouldCreateCollectionFromDataSource() { // GIVEN const auto timestamp = QDateTime::currentMSecsSinceEpoch(); // Data... QFETCH(QString, name); QFETCH(QString, iconName); QFETCH(Domain::DataSource::ContentTypes, contentTypes); QFETCH(bool, isSelected); QStringList mimeTypes; if (contentTypes & Domain::DataSource::Tasks) mimeTypes << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); if (contentTypes & Domain::DataSource::Notes) mimeTypes << QStringLiteral("text/x-vnd.akonadi.note"); // ... stored in a data source auto source = Domain::DataSource::Ptr::create(); source->setName(name); source->setIconName(iconName); source->setContentTypes(contentTypes); source->setSelected(isSelected); source->setProperty("collectionId", 42); // WHEN Akonadi::Serializer serializer; auto collection = serializer.createCollectionFromDataSource(source); // THEN QCOMPARE(collection.id(), source->property("collectionId").value()); QVERIFY(collection.hasAttribute()); QCOMPARE(collection.attribute()->isSelected(), isSelected); QVERIFY(collection.hasAttribute()); QVERIFY(collection.attribute()->timestamp() >= timestamp); } void shouldVerifyIfCollectionIsSelected_data() { QTest::addColumn("mimeTypes"); QTest::addColumn("hasSelectedAttribute"); QTest::addColumn("isSelected"); QTest::addColumn("expectedSelected"); const auto noteMimeTypes = QStringList() << QStringLiteral("text/x-vnd.akonadi.note"); const auto taskMimeTypes = QStringList() << QStringLiteral("application/x-vnd.akonadi.calendar.todo"); const auto bogusMimeTypes = QStringList() << QStringLiteral("foo/bar"); const auto allMimeTypes = noteMimeTypes + taskMimeTypes + bogusMimeTypes; QTest::newRow("nominal case") << allMimeTypes << true << false << false; QTest::newRow("only notes") << noteMimeTypes << true << false << false; QTest::newRow("only tasks") << taskMimeTypes << true << false << false; QTest::newRow("only bogus") << bogusMimeTypes << true << false << false; QTest::newRow("selected, only notes") << noteMimeTypes << true << true << true; QTest::newRow("selected, only tasks") << taskMimeTypes << true << true << true; QTest::newRow("selected, only bogus") << bogusMimeTypes << true << true << false; QTest::newRow("no selected attribute") << allMimeTypes << false << false << true; QTest::newRow("selected attribute (false)") << allMimeTypes << true << false << false; QTest::newRow("selected attribute (true)") << allMimeTypes << true << true << true; QTest::newRow("empty case") << QStringList() << false << false << false; } void shouldVerifyIfCollectionIsSelected() { // GIVEN QFETCH(QStringList, mimeTypes); QFETCH(bool, hasSelectedAttribute); QFETCH(bool, isSelected); Domain::DataSource::ContentTypes expectedContentTypes; if (mimeTypes.contains(QStringLiteral("text/x-vnd.akonadi.note"))) { expectedContentTypes |= Domain::DataSource::Notes; } if (mimeTypes.contains(QStringLiteral("application/x-vnd.akonadi.calendar.todo"))) { expectedContentTypes |= Domain::DataSource::Tasks; } // ... stored in a collection Akonadi::Collection collection(42); collection.setContentMimeTypes(mimeTypes); if (hasSelectedAttribute) { auto selectedAttribute = new Akonadi::ApplicationSelectedAttribute; selectedAttribute->setSelected(isSelected); collection.addAttribute(selectedAttribute); } // WHEN Akonadi::Serializer serializer; // THEN QFETCH(bool, expectedSelected); QCOMPARE(serializer.isSelectedCollection(collection), expectedSelected); } void shouldVerifyCollectionContents_data() { QTest::addColumn("mimeType"); QTest::addColumn("expectedNotes"); QTest::addColumn("expectedTasks"); QTest::newRow("task collection") << "application/x-vnd.akonadi.calendar.todo" << false << true; QTest::newRow("note collection") << "text/x-vnd.akonadi.note" << true << false; } void shouldVerifyCollectionContents() { // GIVEN // Data... QFETCH(QString, mimeType); // ... stored in a collection Akonadi::Collection collection(42); collection.setContentMimeTypes(QStringList() << mimeType); // WHEN Akonadi::Serializer serializer; QFETCH(bool, expectedNotes); QFETCH(bool, expectedTasks); // THEN QCOMPARE(serializer.isNoteCollection(collection), expectedNotes); QCOMPARE(serializer.isTaskCollection(collection), expectedTasks); } void shouldCreateTaskFromItem_data() { QTest::addColumn("summary"); QTest::addColumn("content"); QTest::addColumn("isDone"); QTest::addColumn("doneDate"); QTest::addColumn("startDate"); QTest::addColumn("dueDate"); QTest::addColumn("delegateName"); QTest::addColumn("delegateEmail"); QTest::newRow("nominal case") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "John Doe" << "j@d.com"; QTest::newRow("done case") << "summary" << "content" << true << QDate(2013, 11, 30) << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "John Doe" << "j@d.com"; QTest::newRow("done without doneDate case") << "summary" << "content" << true << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "John Doe" << "j@d.com"; QTest::newRow("empty case") << QString() << QString() << false << QDate() << QDate() << QDate() << QString() << QString(); } void shouldCreateTaskFromItem() { // GIVEN // Data... QFETCH(QString, summary); QFETCH(QString, content); QFETCH(bool, isDone); QFETCH(QDate, doneDate); QFETCH(QDate, startDate); QFETCH(QDate, dueDate); QFETCH(QString, delegateName); QFETCH(QString, delegateEmail); // ... stored in a todo... KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(summary); todo->setDescription(content); if (isDone) todo->setCompleted(QDateTime(doneDate)); else todo->setCompleted(isDone); setTodoDates(todo, startDate, dueDate); todo->setRelatedTo(QStringLiteral("my-uid")); if (!delegateName.isEmpty() || !delegateEmail.isEmpty()) { KCalCore::Attendee::Ptr attendee(new KCalCore::Attendee(delegateName, delegateEmail, true, KCalCore::Attendee::Accepted)); todo->addAttendee(attendee); } // ... as payload of an item Akonadi::Item item; item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // which has a parent collection Akonadi::Collection collection(43); item.setParentCollection(collection); // WHEN Akonadi::Serializer serializer; Domain::Task::Ptr task = serializer.createTaskFromItem(item); auto artifact = serializer.createArtifactFromItem(item).dynamicCast(); // THEN QCOMPARE(task->title(), summary); QCOMPARE(task->text(), content); QCOMPARE(task->isDone(), isDone); QCOMPARE(task->doneDate(), doneDate); QCOMPARE(task->startDate(), startDate); QCOMPARE(task->dueDate(), dueDate); QCOMPARE(task->property("todoUid").toString(), todo->uid()); QCOMPARE(task->property("relatedUid").toString(), todo->relatedTo()); QCOMPARE(task->property("itemId").toLongLong(), item.id()); QCOMPARE(task->property("parentCollectionId").toLongLong(), collection.id()); QCOMPARE(task->delegate().name(), delegateName); QCOMPARE(task->delegate().email(), delegateEmail); QVERIFY(!artifact.isNull()); QCOMPARE(artifact->title(), summary); QCOMPARE(artifact->text(), content); QCOMPARE(artifact->isDone(), isDone); QCOMPARE(artifact->doneDate(), doneDate); QCOMPARE(artifact->startDate(), startDate); QCOMPARE(artifact->dueDate(), dueDate); QCOMPARE(artifact->property("todoUid").toString(), todo->uid()); QCOMPARE(artifact->property("relatedUid").toString(), todo->relatedTo()); QCOMPARE(artifact->property("itemId").toLongLong(), item.id()); QCOMPARE(artifact->property("parentCollectionId").toLongLong(), collection.id()); QCOMPARE(artifact->delegate().name(), delegateName); QCOMPARE(artifact->delegate().email(), delegateEmail); } void shouldCreateNullTaskFromInvalidItem() { // GIVEN Akonadi::Item item; // WHEN Akonadi::Serializer serializer; Domain::Task::Ptr task = serializer.createTaskFromItem(item); auto artifact = serializer.createArtifactFromItem(item); // THEN QVERIFY(task.isNull()); QVERIFY(artifact.isNull()); } void shouldCreateNullTaskFromProjectItem() { // GIVEN // A todo with the project flag KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(QStringLiteral("foo")); todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); // ... as payload of an item Akonadi::Item item; item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // WHEN Akonadi::Serializer serializer; Domain::Task::Ptr task = serializer.createTaskFromItem(item); auto artifact = serializer.createArtifactFromItem(item); // THEN QVERIFY(task.isNull()); QVERIFY(artifact.isNull()); } void shouldUpdateTaskFromItem_data() { QTest::addColumn("updatedSummary"); QTest::addColumn("updatedContent"); QTest::addColumn("updatedDone"); QTest::addColumn("updatedDoneDate"); QTest::addColumn("updatedStartDate"); QTest::addColumn("updatedDueDate"); QTest::addColumn("updatedRelated"); QTest::addColumn("updatedRecurs"); QTest::addColumn("updatedAttachmentData"); QTest::addColumn("updatedAttachmentUris"); QTest::addColumn("updatedAttachmentLabels"); QTest::addColumn("updatedAttachmentMimeTypes"); QTest::addColumn("updatedAttachmentIconNames"); QTest::addColumn("updatedDelegateName"); QTest::addColumn("updatedDelegateEmail"); QTest::addColumn("updatedRunning"); QTest::newRow("no change") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "my-uid" << false << QByteArrayList() << QStringList() << QStringList() << QStringList() << QStringList() << "John Doe" << "j@d.com" << false; QTest::newRow("changed") << "new summary" << "new content" << true << QDate(2013, 11, 28) << QDate(2013, 11, 25) << QDate(2014, 03, 02) << "my-new-uid" << 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"}) << "John Smith" << "j@s.com" << false; QTest::newRow("set_to_running") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << "my-uid" << false << QByteArrayList() << QStringList() << QStringList() << QStringList() << QStringList() << "John Doe" << "j@d.com" << true; } void shouldUpdateTaskFromItem() { // GIVEN // A todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(QStringLiteral("summary")); originalTodo->setDescription(QStringLiteral("content")); originalTodo->setCompleted(false); setTodoDates(originalTodo, QDate(2013, 11, 24), QDate(2014, 03, 01)); originalTodo->setRelatedTo(QStringLiteral("my-uid")); KCalCore::Attendee::Ptr originalAttendee(new KCalCore::Attendee(QStringLiteral("John Doe"), QStringLiteral("j@d.com"), true, KCalCore::Attendee::Accepted)); originalTodo->addAttendee(originalAttendee); // ... as payload of an item... Akonadi::Item originalItem; originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... which has a parent collection... Akonadi::Collection originalCollection(43); originalItem.setParentCollection(originalCollection); // ... deserialized as a task Akonadi::Serializer serializer; auto task = serializer.createTaskFromItem(originalItem); auto artifact = serializer.createArtifactFromItem(originalItem); // WHEN // Data... QFETCH(QString, updatedSummary); QFETCH(QString, updatedContent); QFETCH(bool, updatedDone); QFETCH(QDate, updatedDoneDate); QFETCH(QDate, updatedStartDate); QFETCH(QDate, updatedDueDate); QFETCH(QString, updatedRelated); QFETCH(bool, updatedRecurs); QFETCH(QByteArrayList, updatedAttachmentData); QFETCH(QStringList, updatedAttachmentUris); QFETCH(QStringList, updatedAttachmentLabels); QFETCH(QStringList, updatedAttachmentMimeTypes); QFETCH(QStringList, updatedAttachmentIconNames); QFETCH(QString, updatedDelegateName); QFETCH(QString, updatedDelegateEmail); QFETCH(bool, updatedRunning); // ... in a new todo... KCalCore::Todo::Ptr updatedTodo(new KCalCore::Todo); updatedTodo->setSummary(updatedSummary); updatedTodo->setDescription(updatedContent); if (updatedDone) updatedTodo->setCompleted(KDateTime(updatedDoneDate)); else updatedTodo->setCompleted(updatedDone); setTodoDates(updatedTodo, updatedStartDate, updatedDueDate); updatedTodo->setRelatedTo(updatedRelated); if (updatedRecurs) updatedTodo->recurrence()->setDaily(1); for (int i = 0; i < updatedAttachmentData.size(); i++) { KCalCore::Attachment::Ptr attachment(new KCalCore::Attachment(QByteArray())); if (!updatedAttachmentData.at(i).isEmpty()) attachment->setDecodedData(updatedAttachmentData.at(i)); else attachment->setUri(updatedAttachmentUris.at(i)); attachment->setMimeType(updatedAttachmentMimeTypes.at(i)); attachment->setLabel(updatedAttachmentLabels.at(i)); updatedTodo->addAttachment(attachment); } if (!updatedDelegateName.isEmpty() || !updatedDelegateEmail.isEmpty()) { KCalCore::Attendee::Ptr updatedAttendee(new KCalCore::Attendee(updatedDelegateName, updatedDelegateEmail, true, KCalCore::Attendee::Accepted)); updatedTodo->addAttendee(updatedAttendee); } if (updatedRunning) { updatedTodo->setCustomProperty("Zanshin", "Running", "1"); } else { updatedTodo->removeCustomProperty("Zanshin", "Running"); } // ... as payload of a new item Akonadi::Item updatedItem; updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); updatedItem.setPayload(updatedTodo); // ... which has a new parent collection Akonadi::Collection updatedCollection(45); updatedItem.setParentCollection(updatedCollection); serializer.updateTaskFromItem(task, updatedItem); serializer.updateArtifactFromItem(artifact, updatedItem); // THEN QCOMPARE(task->title(), updatedSummary); QCOMPARE(task->text(), updatedContent); QCOMPARE(task->isDone(), updatedDone); QCOMPARE(task->doneDate(), updatedDoneDate); QCOMPARE(task->startDate(), updatedStartDate); QCOMPARE(task->dueDate(), updatedDueDate); QCOMPARE(task->property("todoUid").toString(), updatedTodo->uid()); QCOMPARE(task->property("relatedUid").toString(), updatedTodo->relatedTo()); QCOMPARE(task->property("itemId").toLongLong(), updatedItem.id()); QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id()); QCOMPARE(task->recurrence(), (updatedRecurs ? Domain::Task::RecursDaily : Domain::Task::NoRecurrence)); QCOMPARE(task->attachments().size(), updatedAttachmentData.size()); for (int i = 0; i < task->attachments().size(); i++) { const auto attachment = task->attachments().at(i); QCOMPARE(attachment.data(), updatedAttachmentData.at(i)); QCOMPARE(attachment.uri(), QUrl(updatedAttachmentUris.at(i))); QCOMPARE(attachment.label(), updatedAttachmentLabels.at(i)); QCOMPARE(attachment.mimeType(), updatedAttachmentMimeTypes.at(i)); QCOMPARE(attachment.iconName(), updatedAttachmentIconNames.at(i)); } QCOMPARE(task->delegate().name(), updatedDelegateName); QCOMPARE(task->delegate().email(), updatedDelegateEmail); QCOMPARE(task->isRunning(), updatedRunning); task = artifact.dynamicCast(); QCOMPARE(task->title(), updatedSummary); QCOMPARE(task->text(), updatedContent); QCOMPARE(task->isDone(), updatedDone); QCOMPARE(task->doneDate(), updatedDoneDate); QCOMPARE(task->startDate(), updatedStartDate); QCOMPARE(task->dueDate(), updatedDueDate); QCOMPARE(task->property("todoUid").toString(), updatedTodo->uid()); QCOMPARE(task->property("relatedUid").toString(), updatedTodo->relatedTo()); QCOMPARE(task->property("itemId").toLongLong(), updatedItem.id()); QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id()); QCOMPARE(task->recurrence(), (updatedRecurs ? Domain::Task::RecursDaily : Domain::Task::NoRecurrence)); QCOMPARE(task->attachments().size(), updatedAttachmentData.size()); for (int i = 0; i < task->attachments().size(); i++) { const auto attachment = task->attachments().at(i); QCOMPARE(attachment.data(), updatedAttachmentData.at(i)); QCOMPARE(attachment.uri(), QUrl(updatedAttachmentUris.at(i))); QCOMPARE(attachment.label(), updatedAttachmentLabels.at(i)); QCOMPARE(attachment.mimeType(), updatedAttachmentMimeTypes.at(i)); QCOMPARE(attachment.iconName(), updatedAttachmentIconNames.at(i)); } QCOMPARE(task->delegate().name(), updatedDelegateName); QCOMPARE(task->delegate().email(), updatedDelegateEmail); QCOMPARE(task->isRunning(), updatedRunning); } void shouldUpdateTaskRecurrenceFromItem_data() { QTest::addColumn("todoRecurrence"); QTest::addColumn("expectedRecurrence"); QTest::newRow("none") << int(KCalCore::Recurrence::rNone) << Domain::Task::NoRecurrence; QTest::newRow("minutely") << int(KCalCore::Recurrence::rMinutely) << Domain::Task::NoRecurrence; QTest::newRow("hourly") << int(KCalCore::Recurrence::rHourly) << Domain::Task::NoRecurrence; QTest::newRow("daily") << int(KCalCore::Recurrence::rDaily) << Domain::Task::RecursDaily; QTest::newRow("weekly") << int(KCalCore::Recurrence::rWeekly) << Domain::Task::RecursWeekly; QTest::newRow("monthly") << int(KCalCore::Recurrence::rMonthlyDay) << Domain::Task::RecursMonthly; } void shouldUpdateTaskRecurrenceFromItem() { // GIVEN // A todo... KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(QStringLiteral("summary")); QFETCH(int, todoRecurrence); switch (todoRecurrence) { case KCalCore::Recurrence::rNone: break; case KCalCore::Recurrence::rMinutely: todo->recurrence()->setMinutely(1); break; case KCalCore::Recurrence::rHourly: todo->recurrence()->setHourly(1); break; case KCalCore::Recurrence::rDaily: todo->recurrence()->setDaily(1); break; case KCalCore::Recurrence::rWeekly: todo->recurrence()->setWeekly(1); break; case KCalCore::Recurrence::rMonthlyDay: todo->recurrence()->setMonthly(1); break; default: qFatal("Shouldn't happen"); } // ... as payload of an item... Akonadi::Item item; item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // ... which has a parent collection... Akonadi::Collection collection(43); item.setParentCollection(collection); // WHEN // ... deserialized as a task Akonadi::Serializer serializer; auto task = serializer.createTaskFromItem(item); // THEN QFETCH(Domain::Task::Recurrence, expectedRecurrence); QCOMPARE(task->recurrence(), expectedRecurrence); } void shouldNotBreakRecurrenceDuringSerialization() { // GIVEN // Data... const QDate today(QDate::currentDate()); const QDate doneDate(2013, 11, 20); const QDate startDate(2013, 11, 10); // ... stored in a todo... KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(QStringLiteral("summary")); -#if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 6, 80) todo->setDtStart(QDateTime(startDate)); -#else - todo->setDtStart(KDateTime(startDate, KDateTime::UTC)); -#endif todo->recurrence()->setMonthly(1); // ... as payload of an item... Akonadi::Item item; item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // ... deserialized as a task Akonadi::Serializer serializer; auto task = serializer.createTaskFromItem(item); // WHEN // Task is marked done... task->setDoneDate(doneDate); task->setDone(true); // and goes through serialization and back const auto newItem = serializer.createItemFromTask(task); serializer.updateTaskFromItem(task, newItem); // THEN QCOMPARE(task->recurrence(), Domain::Task::RecursMonthly); QVERIFY(!task->isDone()); const QDate lastOccurrence(QDate(today.year(), today.month(), 10)); if (today.day() >= 10) QCOMPARE(task->startDate(), lastOccurrence.addMonths(1)); else QCOMPARE(task->startDate(), lastOccurrence); } void shouldNotUpdateTaskFromInvalidItem() { // GIVEN // Data... const QString summary = QStringLiteral("summary"); const QString content = QStringLiteral("content"); const bool isDone = true; const QDate doneDate(2013, 11, 30); const QDate startDate(2013, 11, 24); const QDate dueDate(2014, 03, 01); // ... stored in a todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(summary); originalTodo->setDescription(content); if (originalTodo) originalTodo->setCompleted(KDateTime(doneDate)); else originalTodo->setCompleted(isDone); setTodoDates(originalTodo, startDate, dueDate); // ... as payload of an item... Akonadi::Item originalItem; originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... deserialized as a task Akonadi::Serializer serializer; auto task = serializer.createTaskFromItem(originalItem); auto artifact = serializer.createArtifactFromItem(originalItem); // WHEN Akonadi::Item invalidItem; serializer.updateTaskFromItem(task, invalidItem); serializer.updateArtifactFromItem(artifact, invalidItem); // THEN QCOMPARE(task->title(), summary); QCOMPARE(task->text(), content); QCOMPARE(task->isDone(), isDone); QCOMPARE(task->doneDate(), doneDate); QCOMPARE(task->startDate(), startDate); QCOMPARE(task->dueDate(), dueDate); QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); task = artifact.dynamicCast(); QCOMPARE(task->title(), summary); QCOMPARE(task->text(), content); QCOMPARE(task->isDone(), isDone); QCOMPARE(task->doneDate(), doneDate); QCOMPARE(task->startDate(), startDate); QCOMPARE(task->dueDate(), dueDate); QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); } void shouldNotUpdateTaskFromProjectItem() { // GIVEN // Data... const QString summary = QStringLiteral("summary"); const QString content = QStringLiteral("content"); const bool isDone = true; const QDate doneDate(2013, 11, 30); const QDate startDate(2013, 11, 24); const QDate dueDate(2014, 03, 01); // ... stored in a todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(summary); originalTodo->setDescription(content); if (originalTodo) originalTodo->setCompleted(KDateTime(doneDate)); else originalTodo->setCompleted(isDone); setTodoDates(originalTodo, startDate, dueDate); // ... as payload of an item... Akonadi::Item originalItem; originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... deserialized as a task Akonadi::Serializer serializer; auto task = serializer.createTaskFromItem(originalItem); auto artifact = serializer.createArtifactFromItem(originalItem); // WHEN // A todo with the project flag KCalCore::Todo::Ptr projectTodo(new KCalCore::Todo); projectTodo->setSummary(QStringLiteral("foo")); projectTodo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); // ... as payload of an item Akonadi::Item projectItem; projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); projectItem.setPayload(projectTodo); serializer.updateTaskFromItem(task, projectItem); serializer.updateArtifactFromItem(artifact, projectItem); // THEN QCOMPARE(task->title(), summary); QCOMPARE(task->text(), content); QCOMPARE(task->isDone(), isDone); QCOMPARE(task->doneDate(), doneDate); QCOMPARE(task->startDate(), startDate); QCOMPARE(task->dueDate(), dueDate); QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); task = artifact.dynamicCast(); QCOMPARE(task->title(), summary); QCOMPARE(task->text(), content); QCOMPARE(task->isDone(), isDone); QCOMPARE(task->doneDate(), doneDate); QCOMPARE(task->startDate(), startDate); QCOMPARE(task->dueDate(), dueDate); QCOMPARE(task->property("itemId").toLongLong(), originalItem.id()); } void shouldCreateItemFromTask_data() { QTest::addColumn("summary"); QTest::addColumn("content"); QTest::addColumn("isDone"); QTest::addColumn("doneDate"); QTest::addColumn("startDate"); QTest::addColumn("dueDate"); QTest::addColumn("itemId"); QTest::addColumn("parentCollectionId"); QTest::addColumn("todoUid"); QTest::addColumn("recurrence"); QTest::addColumn("attachments"); QTest::addColumn("delegate"); QTest::addColumn("running"); Domain::Task::Attachments attachments; Domain::Task::Attachment dataAttachment; dataAttachment.setData("foo"); dataAttachment.setLabel("dataAttachment"); dataAttachment.setMimeType("text/plain"); dataAttachment.setIconName("text-plain"); attachments.append(dataAttachment); Domain::Task::Attachment uriAttachment; uriAttachment.setUri(QUrl("https://www.kde.org")); uriAttachment.setLabel("uriAttachment"); uriAttachment.setMimeType("text/html"); uriAttachment.setIconName("text-html"); attachments.append(uriAttachment); QTest::newRow("nominal case (no id)") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::NoRecurrence << attachments << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("nominal case (daily)") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::RecursDaily << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("nominal case (weekly)") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::RecursWeekly << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("nominal case (monthly)") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::RecursMonthly << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("done case (no id)") << "summary" << "content" << true << QDate(2013, 11, 30) << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("empty case (no id)") << QString() << QString() << false << QDate() << QDate() << QDate() << qint64(-1) << qint64(-1) << QString() << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate() << false; #if 0 // if we ever need time info, then we need a Task::setAllDay(bool) just like KCalCore::Todo has. QTest::newRow("nominal_with_time_info_noid") << "summary" << "content" << true << QDateTime(QDate(2015, 3, 1), QTime(1, 2, 3), Qt::UTC) << QDateTime(QDate(2013, 11, 24), QTime(0, 1, 2), Qt::UTC) << QDateTime(QDate(2016, 3, 1), QTime(4, 5, 6), Qt::UTC) << qint64(-1) << qint64(-1) << QString() << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; #endif QTest::newRow("nominal case (with id)") << "summary" << "content" << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(42) << qint64(43) << "my-uid" << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("done case (with id)") << "summary" << "content" << true << QDate(2013, 11, 30) << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(42) << qint64(43) << "my-uid" << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) << false; QTest::newRow("empty case (with id)") << QString() << QString() << false << QDate() << QDate() << QDate() << qint64(42) << qint64(43) << "my-uid" << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate() << false; QTest::newRow("nominal case (running)") << "running" << QString() << false << QDate() << QDate(2013, 11, 24) << QDate(2014, 03, 01) << qint64(-1) << qint64(-1) << QString() << Domain::Task::NoRecurrence << Domain::Task::Attachments() << Domain::Task::Delegate() << true; } void shouldCreateItemFromTask() { // GIVEN // Data... QFETCH(QString, summary); QFETCH(QString, content); QFETCH(bool, isDone); QFETCH(QDate, doneDate); QFETCH(QDate, startDate); QFETCH(QDate, dueDate); QFETCH(qint64, itemId); QFETCH(qint64, parentCollectionId); QFETCH(QString, todoUid); QFETCH(Domain::Task::Recurrence, recurrence); QFETCH(Domain::Task::Attachments, attachments); QFETCH(Domain::Task::Delegate, delegate); QFETCH(bool, running); // ... stored in a task auto task = Domain::Task::Ptr::create(); task->setTitle(summary); task->setText(content); task->setDone(isDone); task->setDoneDate(doneDate); task->setStartDate(startDate); task->setDueDate(dueDate); task->setRecurrence(recurrence); task->setAttachments(attachments); task->setDelegate(delegate); task->setRunning(running); if (itemId > 0) task->setProperty("itemId", itemId); if (parentCollectionId > 0) task->setProperty("parentCollectionId", parentCollectionId); if (!todoUid.isEmpty()) task->setProperty("todoUid", todoUid); task->setProperty("relatedUid", "parent-uid"); // WHEN Akonadi::Serializer serializer; auto item = serializer.createItemFromTask(task); // THEN QCOMPARE(item.mimeType(), KCalCore::Todo::todoMimeType()); QCOMPARE(item.isValid(), itemId > 0); if (itemId > 0) { QCOMPARE(item.id(), itemId); } QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0); if (parentCollectionId > 0) { QCOMPARE(item.parentCollection().id(), parentCollectionId); } auto todo = item.payload(); QCOMPARE(todo->summary(), summary); QCOMPARE(todo->description(), content); QCOMPARE(todo->isCompleted(), isDone); -#if KCALCORE_VERSION >= QT_VERSION_CHECK(5, 6, 80) QCOMPARE(todo->completed().toLocalTime().date(), doneDate); QCOMPARE(todo->dtStart().toLocalTime().date(), startDate); QCOMPARE(todo->dtDue().toLocalTime().date(), dueDate); if (todo->dtStart().isValid()) { QCOMPARE(int(todo->dtStart().timeSpec()), int(Qt::LocalTime)); } QVERIFY(todo->allDay()); // this is always true currently... -#else - QCOMPARE(todo->completed().dateTime().date(), doneDate); - QCOMPARE(todo->dtStart().dateTime().date(), startDate); - QCOMPARE(todo->dtDue().dateTime().date(), dueDate); - if (todo->dtStart().isValid()) { - QCOMPARE(int(todo->dtStart().timeType()), int(KDateTime::LocalTime)); - } - QCOMPARE(todo->dtStart().isDateOnly(), todo->allDay()); - -#endif const ushort expectedRecurrence = recurrence == Domain::Task::NoRecurrence ? KCalCore::Recurrence::rNone : recurrence == Domain::Task::RecursDaily ? KCalCore::Recurrence::rDaily : recurrence == Domain::Task::RecursWeekly ? KCalCore::Recurrence::rWeekly : recurrence == Domain::Task::RecursMonthly ? KCalCore::Recurrence::rMonthlyDay : KCalCore::Recurrence::rNone; // Shouldn't happen though QCOMPARE(todo->recurrence()->recurrenceType(), expectedRecurrence); if (recurrence != Domain::Task::NoRecurrence) QCOMPARE(todo->recurrence()->frequency(), 1); QCOMPARE(todo->attachments().size(), attachments.size()); for (int i = 0; i < attachments.size(); i++) { auto attachment = todo->attachments().at(i); QCOMPARE(attachment->isUri(), attachments.at(i).isUri()); QCOMPARE(QUrl(attachment->uri()), attachments.at(i).uri()); QCOMPARE(attachment->decodedData(), attachments.at(i).data()); QCOMPARE(attachment->label(), attachments.at(i).label()); QCOMPARE(attachment->mimeType(), attachments.at(i).mimeType()); } if (delegate.isValid()) { auto attendee = todo->attendeeByMail(delegate.email()); QVERIFY(attendee); QCOMPARE(attendee->name(), delegate.name()); QCOMPARE(attendee->email(), delegate.email()); } if (!todoUid.isEmpty()) { QCOMPARE(todo->uid(), todoUid); } QCOMPARE(todo->relatedTo(), QStringLiteral("parent-uid")); QCOMPARE(todo->customProperty("Zanshin", "Running"), running ? QStringLiteral("1") : QString()); } void shouldVerifyIfAnItemIsATaskChild_data() { QTest::addColumn("task"); QTest::addColumn("item"); QTest::addColumn("isParent"); // Create task const QString summary = QStringLiteral("summary"); const QString content = QStringLiteral("content"); const bool isDone = true; const QDate doneDate(QDate(2013, 11, 30)); const QDate startDate(QDate(2013, 11, 24)); const QDate dueDate(QDate(2014, 03, 01)); // ... create a task Domain::Task::Ptr task(new Domain::Task); task->setTitle(summary); task->setText(content); task->setDone(isDone); task->setDoneDate(doneDate); task->setStartDate(startDate); task->setDueDate(dueDate); task->setProperty("todoUid", "1"); // Create Child item KCalCore::Todo::Ptr childTodo(new KCalCore::Todo); childTodo->setSummary(summary); childTodo->setDescription(content); if (isDone) childTodo->setCompleted(KDateTime(doneDate)); else childTodo->setCompleted(isDone); setTodoDates(childTodo, startDate, dueDate); Akonadi::Item childItem; childItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); childItem.setPayload(childTodo); QTest::newRow("without parent") << task << childItem << false; // Create Child Item with parent KCalCore::Todo::Ptr childTodo2(new KCalCore::Todo); childTodo2->setSummary(summary); childTodo2->setDescription(content); if (isDone) childTodo2->setCompleted(KDateTime(doneDate)); else childTodo2->setCompleted(isDone); setTodoDates(childTodo2, startDate, dueDate); childTodo2->setRelatedTo(QStringLiteral("1")); Akonadi::Item childItem2; childItem2.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); childItem2.setPayload(childTodo2); QTest::newRow("with parent") << task << childItem2 << true; Domain::Task::Ptr invalidTask(new Domain::Task); QTest::newRow("with invalid task") << invalidTask << childItem << false; Akonadi::Item invalidItem; QTest::newRow("with invalid item") << task << invalidItem << false; } void shouldVerifyIfAnItemIsATaskChild() { // GIVEN QFETCH(Domain::Task::Ptr, task); QFETCH(Akonadi::Item, item); QFETCH(bool, isParent); // WHEN Akonadi::Serializer serializer; bool value = serializer.isTaskChild(task, item); // THEN QCOMPARE(value, isParent); } void shouldRetrieveRelatedUidFromItem_data() { QTest::addColumn("item"); QTest::addColumn("expectedUid"); Akonadi::Item item1; KCalCore::Todo::Ptr todo1(new KCalCore::Todo); item1.setPayload(todo1); Akonadi::Item item2; KCalCore::Todo::Ptr todo2(new KCalCore::Todo); todo2->setRelatedTo(QStringLiteral("1")); item2.setPayload(todo2); Akonadi::Item item3; KMime::Message::Ptr message1(new KMime::Message); message1->subject(true)->fromUnicodeString(QStringLiteral("foo"), "utf-8"); message1->mainBodyPart()->fromUnicodeString(QStringLiteral("bar")); item3.setMimeType(Akonadi::NoteUtils::noteMimeType()); item3.setPayload(message1); Akonadi::Item item4; KMime::Message::Ptr message2(new KMime::Message); message2->subject(true)->fromUnicodeString(QStringLiteral("foo"), "utf-8"); message2->mainBodyPart()->fromUnicodeString(QStringLiteral("bar")); auto relatedHeader1 = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader1->from7BitString("1"); message2->appendHeader(relatedHeader1); item4.setMimeType(Akonadi::NoteUtils::noteMimeType()); item4.setPayload(message2); Akonadi::Item item5; KMime::Message::Ptr message3(new KMime::Message); message3->subject(true)->fromUnicodeString(QStringLiteral("foo"), "utf-8"); message3->mainBodyPart()->fromUnicodeString(QStringLiteral("bar")); auto relatedHeader2 = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); message3->appendHeader(relatedHeader2); item5.setMimeType(Akonadi::NoteUtils::noteMimeType()); item5.setPayload(message3); QTest::newRow("task without related") << item1 << QString(); QTest::newRow("task with related") << item2 << "1"; QTest::newRow("note without related") << item3 << QString(); QTest::newRow("note with related") << item4 << "1"; QTest::newRow("note with empty related") << item5 << QString(); } void shouldRetrieveRelatedUidFromItem() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(QString, expectedUid); // WHEN Akonadi::Serializer serializer; QString uid = serializer.relatedUidFromItem(item); // THEN QCOMPARE(uid, expectedUid); } void shouldCreateNoteFromItem_data() { QTest::addColumn("title"); QTest::addColumn("text"); QTest::addColumn("relatedUid"); QTest::newRow("nominal case (no related)") << "A note title" << "A note content.\nWith two lines." << QString(); QTest::newRow("nominal case (with related)") << "A note title" << "A note content.\nWith two lines." << "parent-uid"; QTest::newRow("trailing new lines") << "A note title" << "Empty lines at the end.\n\n\n" << QString(); QTest::newRow("empty case") << QString() << QString() << QString(); } void shouldCreateNoteFromItem() { // GIVEN // Data... QFETCH(QString, title); QFETCH(QString, text); QFETCH(QString, relatedUid); // ... stored in a message... KMime::Message::Ptr message(new KMime::Message); message->subject(true)->fromUnicodeString(title, "utf-8"); message->mainBodyPart()->fromUnicodeString(text); if (!relatedUid.isEmpty()) { auto relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString(relatedUid.toUtf8()); message->appendHeader(relatedHeader); } // ... as payload of an item. Akonadi::Item item; item.setMimeType(Akonadi::NoteUtils::noteMimeType()); item.setPayload(message); // WHEN Akonadi::Serializer serializer; Domain::Note::Ptr note = serializer.createNoteFromItem(item); auto artifact = serializer.createArtifactFromItem(item).dynamicCast(); // THEN const auto expectedText = text.endsWith('\n') ? (text.chop(1), text) : text; QCOMPARE(note->title(), title); QCOMPARE(note->text(), expectedText); QCOMPARE(note->property("itemId").toLongLong(), item.id()); QCOMPARE(note->property("relatedUid").toString(), relatedUid); QVERIFY(!artifact.isNull()); QCOMPARE(artifact->title(), title); QCOMPARE(artifact->text(), expectedText); QCOMPARE(artifact->property("itemId").toLongLong(), item.id()); QCOMPARE(artifact->property("relatedUid").toString(), relatedUid); } void shouldCreateNullNoteFromInvalidItem() { // GIVEN Akonadi::Item item; // WHEN Akonadi::Serializer serializer; Domain::Note::Ptr note = serializer.createNoteFromItem(item); auto artifact = serializer.createArtifactFromItem(item); // THEN QVERIFY(note.isNull()); QVERIFY(artifact.isNull()); } void shouldUpdateNoteFromItem_data() { QTest::addColumn("updatedTitle"); QTest::addColumn("updatedText"); QTest::addColumn("updatedRelatedUid"); QTest::newRow("no change") << "title" << "content" << "parent-uid"; QTest::newRow("data changed (with related)") << "A new title" << "A new content" << "new-parent-uid"; QTest::newRow("data changed (with no related)") << "A new title" << "A new content" << QString(); } void shouldUpdateNoteFromItem() { // GIVEN // A message... KMime::Message::Ptr message(new KMime::Message); message->subject(true)->fromUnicodeString(QStringLiteral("title"), "utf-8"); message->mainBodyPart()->fromUnicodeString(QStringLiteral("text")); auto relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString("parent-uid"); message->appendHeader(relatedHeader); //... as the payload of an item... Akonadi::Item item; item.setMimeType(Akonadi::NoteUtils::noteMimeType()); item.setPayload(message); //... deserialized as a note Akonadi::Serializer serializer; auto note = serializer.createNoteFromItem(item); auto artifact = serializer.createNoteFromItem(item); // WHEN // Data... QFETCH(QString, updatedTitle); QFETCH(QString, updatedText); QFETCH(QString, updatedRelatedUid); //... stored in a new message... KMime::Message::Ptr updatedMessage(new KMime::Message); updatedMessage->subject(true)->fromUnicodeString(updatedTitle, "utf-8"); updatedMessage->mainBodyPart()->fromUnicodeString(updatedText); if (!updatedRelatedUid.isEmpty()) { relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString(updatedRelatedUid.toUtf8()); updatedMessage->appendHeader(relatedHeader); } //... as the payload of a new item... Akonadi::Item updatedItem; updatedItem.setMimeType(Akonadi::NoteUtils::noteMimeType()); updatedItem.setPayload(updatedMessage); serializer.updateNoteFromItem(note, updatedItem); serializer.updateArtifactFromItem(artifact, updatedItem); // THEN QCOMPARE(note->title(), updatedTitle); QCOMPARE(note->text(), updatedText); QCOMPARE(note->property("itemId").toLongLong(), updatedItem.id()); QCOMPARE(note->property("relatedUid").toString(), updatedRelatedUid); note = artifact.dynamicCast(); QCOMPARE(note->title(), updatedTitle); QCOMPARE(note->text(), updatedText); QCOMPARE(note->property("itemId").toLongLong(), updatedItem.id()); QCOMPARE(note->property("relatedUid").toString(), updatedRelatedUid); } void shouldNotUpdateNoteFromInvalidItem() { // GIVEN // Data... QString title = QStringLiteral("A title"); QString text = QStringLiteral("A note content"); // ... stored in a message... KMime::Message::Ptr message(new KMime::Message); message->subject(true)->fromUnicodeString(title, "utf-8"); message->mainBodyPart()->fromUnicodeString(text); //... as the payload of an item... Akonadi::Item item; item.setMimeType(Akonadi::NoteUtils::noteMimeType()); item.setPayload(message); //... deserialized as a note Akonadi::Serializer serializer; auto note = serializer.createNoteFromItem(item); auto artifact = serializer.createArtifactFromItem(item); // WHEN Akonadi::Item invalidItem; serializer.updateNoteFromItem(note, invalidItem); serializer.updateArtifactFromItem(artifact, invalidItem); //THEN QCOMPARE(note->title(), title); QCOMPARE(note->text(), text); QCOMPARE(note->property("itemId").toLongLong(), item.id()); note = artifact.dynamicCast(); QCOMPARE(note->title(), title); QCOMPARE(note->text(), text); QCOMPARE(note->property("itemId").toLongLong(), item.id()); } void shouldCreateItemFromNote_data() { QTest::addColumn("title"); QTest::addColumn("content"); QTest::addColumn("expectedTitle"); QTest::addColumn("expectedContent"); QTest::addColumn("itemId"); QTest::addColumn("relatedUid"); QTest::newRow("nominal case (no id)") << "title" << "content" << "title" << "content" << qint64(-1) << QString(); QTest::newRow("empty case (no id)") << QString() << QString() << "New Note" << QString() << qint64(-1) << QString(); QTest::newRow("nominal case (with id)") << "title" << "content" << "title" << "content" << qint64(42) << "parent-uid"; QTest::newRow("empty case (with id)") << QString() << QString() << "New Note" << QString() << qint64(42) << "parent-uid"; QTest::newRow("empty line at the end") << "title" << "content\n\n\n" << "title" << "content\n\n\n" << qint64(-1) << QString(); } void shouldCreateItemFromNote() { // GIVEN // Data... QFETCH(QString, title); QFETCH(QString, content); QFETCH(qint64, itemId); QFETCH(QString, relatedUid); // ... stored in a note auto note = Domain::Note::Ptr::create(); note->setTitle(title); note->setText(content); if (itemId > 0) note->setProperty("itemId", itemId); if (!relatedUid.isEmpty()) note->setProperty("relatedUid", relatedUid); // WHEN Akonadi::Serializer serializer; auto item = serializer.createItemFromNote(note); // THEN QCOMPARE(item.mimeType(), Akonadi::NoteUtils::noteMimeType()); QCOMPARE(item.isValid(), itemId > 0); if (itemId > 0) { QCOMPARE(item.id(), itemId); } QFETCH(QString, expectedTitle); QFETCH(QString, expectedContent); auto message = item.payload(); QCOMPARE(message->subject(false)->asUnicodeString(), expectedTitle); QCOMPARE(message->mainBodyPart()->decodedText(), expectedContent); if (relatedUid.isEmpty()) { QVERIFY(!message->headerByType("X-Zanshin-RelatedProjectUid")); } else { QVERIFY(message->headerByType("X-Zanshin-RelatedProjectUid")); QCOMPARE(message->headerByType("X-Zanshin-RelatedProjectUid")->asUnicodeString(), relatedUid); } } void shouldCreateProjectFromItem_data() { QTest::addColumn("summary"); QTest::newRow("nominal case") << "summary"; QTest::newRow("empty case") << QString(); } void shouldCreateProjectFromItem() { // GIVEN // Data... QFETCH(QString, summary); // ... stored in a todo... KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(summary); todo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); QVERIFY(!todo->uid().isEmpty()); // ... as payload of an item Akonadi::Item item(42); item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // which has a prent collection Akonadi::Collection collection(43); item.setParentCollection(collection); // WHEN Akonadi::Serializer serializer; Domain::Project::Ptr project = serializer.createProjectFromItem(item); // THEN QCOMPARE(project->name(), summary); QCOMPARE(project->property("itemId").toLongLong(), item.id()); QCOMPARE(project->property("parentCollectionId").toLongLong(), collection.id()); QCOMPARE(project->property("todoUid").toString(), todo->uid()); } void shouldCreateNullProjectFromInvalidItem() { // GIVEN Akonadi::Item item; // WHEN Akonadi::Serializer serializer; Domain::Project::Ptr project = serializer.createProjectFromItem(item); // THEN QVERIFY(project.isNull()); } void shouldCreateNullProjectFromTaskItem() { // GIVEN // A todo without the project flag KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setSummary(QStringLiteral("foo")); // ... as payload of an item Akonadi::Item item; item.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); item.setPayload(todo); // WHEN Akonadi::Serializer serializer; Domain::Project::Ptr project = serializer.createProjectFromItem(item); // THEN QVERIFY(project.isNull()); } void shouldUpdateProjectFromItem_data() { QTest::addColumn("updatedSummary"); QTest::newRow("no change") << "summary"; QTest::newRow("changed") << "new summary"; } void shouldUpdateProjectFromItem() { // GIVEN // A todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(QStringLiteral("summary")); originalTodo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); // ... as payload of an item... Akonadi::Item originalItem(42); originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... which has a parent collection... Akonadi::Collection originalCollection(43); originalItem.setParentCollection(originalCollection); // ... deserialized as a project Akonadi::Serializer serializer; auto project = serializer.createProjectFromItem(originalItem); // WHEN // Data... QFETCH(QString, updatedSummary); // ... in a new todo... KCalCore::Todo::Ptr updatedTodo(new KCalCore::Todo); updatedTodo->setSummary(updatedSummary); updatedTodo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); QVERIFY(!updatedTodo->uid().isEmpty()); // ... as payload of a new item Akonadi::Item updatedItem(44); updatedItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); updatedItem.setPayload(updatedTodo); // ... which has a new parent collection Akonadi::Collection updatedCollection(45); updatedItem.setParentCollection(updatedCollection); serializer.updateProjectFromItem(project, updatedItem); // THEN QCOMPARE(project->name(), updatedSummary); QCOMPARE(project->property("itemId").toLongLong(), updatedItem.id()); QCOMPARE(project->property("parentCollectionId").toLongLong(), updatedCollection.id()); QCOMPARE(project->property("todoUid").toString(), updatedTodo->uid()); } void shouldNotUpdateProjectFromInvalidItem() { // GIVEN // Data... const QString summary = QStringLiteral("summary"); // ... stored in a todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(summary); originalTodo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); // ... as payload of an item... Akonadi::Item originalItem; originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... deserialized as a project Akonadi::Serializer serializer; auto project = serializer.createProjectFromItem(originalItem); // WHEN Akonadi::Item invalidItem; serializer.updateProjectFromItem(project, invalidItem); // THEN QCOMPARE(project->name(), summary); } void shouldNotUpdateProjectFromTaskItem() { // GIVEN // Data... const QString summary = QStringLiteral("summary"); // ... stored in a todo... KCalCore::Todo::Ptr originalTodo(new KCalCore::Todo); originalTodo->setSummary(summary); originalTodo->setCustomProperty("Zanshin", "Project", QStringLiteral("1")); // ... as payload of an item... Akonadi::Item originalItem; originalItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); originalItem.setPayload(originalTodo); // ... deserialized as a project Akonadi::Serializer serializer; auto project = serializer.createProjectFromItem(originalItem); // WHEN // A todo without the project flag KCalCore::Todo::Ptr projectTodo(new KCalCore::Todo); projectTodo->setSummary(QStringLiteral("foo")); // ... as payload of an item Akonadi::Item projectItem; projectItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); projectItem.setPayload(projectTodo); serializer.updateProjectFromItem(project, projectItem); // THEN QCOMPARE(project->name(), summary); } void shouldCreateItemFromProject_data() { QTest::addColumn("summary"); QTest::addColumn("itemId"); QTest::addColumn("parentCollectionId"); QTest::newRow("nominal case (no id)") << "summary" << qint64(-1) << qint64(-1); QTest::newRow("empty case (no id)") << QString() << qint64(-1) << qint64(-1); QTest::newRow("nominal case (with id)") << "summary" << qint64(42) << qint64(43); QTest::newRow("empty case (with id)") << QString() << qint64(42) << qint64(43); } void shouldCreateItemFromProject() { // GIVEN // Data... QFETCH(QString, summary); QFETCH(qint64, itemId); QFETCH(qint64, parentCollectionId); const QString todoUid = QStringLiteral("test-uid"); // ... stored in a project auto project = Domain::Project::Ptr::create(); project->setName(summary); project->setProperty("todoUid", todoUid); if (itemId > 0) project->setProperty("itemId", itemId); if (parentCollectionId > 0) project->setProperty("parentCollectionId", parentCollectionId); // WHEN Akonadi::Serializer serializer; auto item = serializer.createItemFromProject(project); // THEN QCOMPARE(item.mimeType(), KCalCore::Todo::todoMimeType()); QCOMPARE(item.isValid(), itemId > 0); if (itemId > 0) { QCOMPARE(item.id(), itemId); } QCOMPARE(item.parentCollection().isValid(), parentCollectionId > 0); if (parentCollectionId > 0) { QCOMPARE(item.parentCollection().id(), parentCollectionId); } auto todo = item.payload(); QCOMPARE(todo->summary(), summary); QCOMPARE(todo->uid(), todoUid); QVERIFY(!todo->customProperty("Zanshin", "Project").isEmpty()); } void shouldVerifyIfAnItemIsAProjectChild_data() { QTest::addColumn("project"); QTest::addColumn("item"); QTest::addColumn("isParent"); // Create project auto project = Domain::Project::Ptr::create(); project->setName(QStringLiteral("project")); project->setProperty("todoUid", "1"); // Create unrelated todo auto unrelatedTodo = KCalCore::Todo::Ptr::create(); unrelatedTodo->setSummary(QStringLiteral("summary")); Akonadi::Item unrelatedTodoItem; unrelatedTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); unrelatedTodoItem.setPayload(unrelatedTodo); QTest::newRow("unrelated todo") << project << unrelatedTodoItem << false; // Create child todo auto childTodo = KCalCore::Todo::Ptr::create(); childTodo->setSummary(QStringLiteral("summary")); childTodo->setRelatedTo(QStringLiteral("1")); Akonadi::Item childTodoItem; childTodoItem.setMimeType(QStringLiteral("application/x-vnd.akonadi.calendar.todo")); childTodoItem.setPayload(childTodo); QTest::newRow("child todo") << project << childTodoItem << true; // Create unrelated note KMime::Message::Ptr unrelatedNote(new KMime::Message); unrelatedNote->subject(true)->fromUnicodeString(QStringLiteral("subject"), "utf-8"); Akonadi::Item unrelatedNoteItem; unrelatedNoteItem.setMimeType(Akonadi::NoteUtils::noteMimeType()); unrelatedNoteItem.setPayload(unrelatedNote); QTest::newRow("unrelated note") << project << unrelatedNoteItem << false; // Create child note KMime::Message::Ptr childNote(new KMime::Message); childNote->subject(true)->fromUnicodeString(QStringLiteral("subject"), "utf-8"); auto relatedHeader = new KMime::Headers::Generic("X-Zanshin-RelatedProjectUid"); relatedHeader->from7BitString("1"); childNote->appendHeader(relatedHeader); Akonadi::Item childNoteItem; childNoteItem.setMimeType(Akonadi::NoteUtils::noteMimeType()); childNoteItem.setPayload(childNote); QTest::newRow("child todo") << project << childNoteItem << true; auto invalidProject = Domain::Project::Ptr::create(); QTest::newRow("invalid project") << invalidProject << unrelatedNoteItem << false; Akonadi::Item invalidItem; QTest::newRow("invalid item") << project << invalidItem << false; } void shouldVerifyIfAnItemIsAProjectChild() { // GIVEN QFETCH(Domain::Project::Ptr, project); QFETCH(Akonadi::Item, item); QFETCH(bool, isParent); // WHEN Akonadi::Serializer serializer; bool value = serializer.isProjectChild(project, item); // THEN QCOMPARE(value, isParent); } void shouldUpdateItemParent_data() { QTest::addColumn("item"); QTest::addColumn("parent"); QTest::addColumn("expectedRelatedToUid"); Akonadi::Item item1; KCalCore::Todo::Ptr todo1(new KCalCore::Todo); item1.setPayload(todo1); Domain::Task::Ptr parent(new Domain::Task); parent->setProperty("todoUid", "1"); QTest::newRow("nominal case") << item1 << parent << "1"; Akonadi::Item item2; QTest::newRow("update item without payload") << item2 << parent << QString(); Domain::Task::Ptr parent2(new Domain::Task); QTest::newRow("update item with a empty parent uid") << item1 << parent2 << QString(); } void shouldUpdateItemParent() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(Domain::Task::Ptr, parent); QFETCH(QString, expectedRelatedToUid); // WHEN Akonadi::Serializer serializer; serializer.updateItemParent(item, parent); // THEN if (item.hasPayload()) { auto todo = item.payload(); QString relatedUid = todo->relatedTo(); QCOMPARE(relatedUid, expectedRelatedToUid); } } void shouldUpdateItemProject_data() { QTest::addColumn("item"); QTest::addColumn("parent"); QTest::addColumn("expectedRelatedToUid"); Akonadi::Item todoItem; KCalCore::Todo::Ptr todo(new KCalCore::Todo); todoItem.setPayload(todo); auto parent = Domain::Project::Ptr::create(); parent->setProperty("todoUid", "1"); QTest::newRow("nominal todo case") << todoItem << parent << "1"; auto invalidParent = Domain::Project::Ptr::create(); QTest::newRow("update todo item with a empty parent uid") << todoItem << invalidParent << QString(); Akonadi::Item noteItem; KMime::Message::Ptr note(new KMime::Message); noteItem.setPayload(note); QTest::newRow("nominal note case") << noteItem << parent << "1"; QTest::newRow("update note item with a empty parent uid") << noteItem << invalidParent << QString(); Akonadi::Item invalidItem; QTest::newRow("update item without payload") << invalidItem << parent << QString(); } void shouldUpdateItemProject() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(Domain::Project::Ptr, parent); QFETCH(QString, expectedRelatedToUid); // WHEN Akonadi::Serializer serializer; serializer.updateItemProject(item, parent); // THEN if (item.hasPayload()) { auto todo = item.payload(); const QString relatedUid = todo->relatedTo(); QCOMPARE(relatedUid, expectedRelatedToUid); } else if (item.hasPayload()) { auto note = item.payload(); const auto relatedHeader = note->headerByType("X-Zanshin-RelatedProjectUid"); const QString relatedUid = relatedHeader ? relatedHeader->asUnicodeString() : QString(); QCOMPARE(relatedUid, expectedRelatedToUid); if (!expectedRelatedToUid.isEmpty()) QVERIFY(note->encodedContent().contains(QStringLiteral("X-Zanshin-RelatedProjectUid: %1").arg(expectedRelatedToUid).toUtf8())); else QVERIFY(!note->encodedContent().contains("X-Zanshin-RelatedProjectUid:")); } } void shouldFilterChildrenItem_data() { QTest::addColumn("item"); QTest::addColumn("items"); QTest::addColumn("size"); Akonadi::Item item(12); KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setUid(QStringLiteral("1")); item.setPayload(todo); Akonadi::Item::List items; QTest::newRow("empty list") << item << items << 0; Akonadi::Item item2(13); KCalCore::Todo::Ptr todo2(new KCalCore::Todo); item2.setPayload(todo2); Akonadi::Item::List items2; items2 << item2; QTest::newRow("list without child") << item << items2 << 0; Akonadi::Item item3(14); KCalCore::Todo::Ptr todo3(new KCalCore::Todo); todo3->setUid(QStringLiteral("3")); todo3->setRelatedTo(QStringLiteral("1")); item3.setPayload(todo3); Akonadi::Item::List items3; items3 << item2 << item3; QTest::newRow("list with child") << item << items3 << 1; Akonadi::Item item4(15); KCalCore::Todo::Ptr todo4(new KCalCore::Todo); todo4->setRelatedTo(QStringLiteral("3")); item4.setPayload(todo4); Akonadi::Item::List items4; items4 << item2 << item3 << item4; QTest::newRow("list with child with a child") << item << items4 << 2; Akonadi::Item::List items5; items5 << item << item2 << item3 << item4; QTest::newRow("list with filter in list") << item << items5 << 2; } void shouldFilterChildrenItem() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(Akonadi::Item::List, items); QFETCH(int, size); // WHEN Akonadi::Serializer serializer; Akonadi::Item::List list = serializer.filterDescendantItems(items, item); // THEN QCOMPARE(list.size(), size); } void shouldRemoveItemParent_data() { QTest::addColumn("item"); Akonadi::Item item(15); KCalCore::Todo::Ptr todo(new KCalCore::Todo); todo->setRelatedTo(QStringLiteral("3")); item.setPayload(todo); QTest::newRow("nominal case") << item; Akonadi::Item item2(16); QTest::newRow("parent invalid") << item2; } void shouldRemoveItemParent() { // GIVEN QFETCH(Akonadi::Item, item); // WHEN Akonadi::Serializer serializer; serializer.removeItemParent(item); // THEN if (item.hasPayload()) QCOMPARE(item.payload()->relatedTo(), QString()); } void shouldPromoteItemToProject_data() { QTest::addColumn("item"); auto item = Akonadi::Item(15); auto todo = KCalCore::Todo::Ptr::create(); todo->setRelatedTo(QStringLiteral("3")); item.setPayload(todo); QTest::newRow("nominal case") << item; QTest::newRow("invalid item") << Akonadi::Item(16); } void shouldPromoteItemToProject() { // GIVEN QFETCH(Akonadi::Item, item); // WHEN Akonadi::Serializer serializer; serializer.promoteItemToProject(item); // THEN if (item.hasPayload()) { auto todo = item.payload(); QCOMPARE(todo->relatedTo(), QString()); QVERIFY(!todo->customProperty("Zanshin", "Project").isEmpty()); } } void shouldClearItem_data() { QTest::addColumn("item"); Akonadi::Item *itemWithContent = new Akonadi::Item(15); KCalCore::Todo::Ptr todo(new KCalCore::Todo); // context Akonadi::Tag context(QStringLiteral("42")); context.setType( Akonadi::SerializerInterface::contextTagType() ); // tag Akonadi::Tag tag(QStringLiteral("43")); tag.setType( Akonadi::Tag::PLAIN ); Akonadi::Tag::List tagsList = Akonadi::Tag::List() << tag << context; itemWithContent->setTags(tagsList); itemWithContent->setPayload(todo); QTest::newRow("nominal case") << itemWithContent; Akonadi::Item *item2 = new Akonadi::Item(16); QTest::newRow("parent invalid") << item2; } void shouldClearItem() { // GIVEN QFETCH(Akonadi::Item*, item); // WHEN Akonadi::Serializer serializer; serializer.clearItem(item); // THEN QCOMPARE(item->tags().size(), 0); delete item; } void shouldCreateContextFromTag_data() { QTest::addColumn("type"); QTest::addColumn("name"); QTest::addColumn("tagId"); const QByteArray rightTagType = Akonadi::Serializer::contextTagType() ; QTest::newRow("nominal case") << rightTagType << "Context42" << Akonadi::Tag::Id(42); QTest::newRow("empty name case") << rightTagType << "" << Akonadi::Tag::Id(43); } void shouldCreateContextFromTag() { // GIVEN // Data... QFETCH(QByteArray, type); QFETCH(QString, name); QFETCH(Akonadi::Tag::Id, tagId); // ... stored as an Akonadi Tag Akonadi::Tag tag(name); tag.setType(type); tag.setId(tagId); // WHEN Akonadi::Serializer serializer; Domain::Context::Ptr context = serializer.createContextFromTag(tag); // THEN QCOMPARE(context->name(), tag.name()); QCOMPARE(context->property("tagId").toLongLong(), tag.id()); } void shouldNotCreateContextFromWrongTagType() { // GIVEN // Data stored as an Akonadi Tag Akonadi::Tag tag(QStringLiteral("context42")); tag.setType(QByteArray("wrongTagType")); // WHEN Akonadi::Serializer serializer; Domain::Context::Ptr context = serializer.createContextFromTag(tag); // THEN QVERIFY(!context); } void shouldUpdateContextFromTag_data() { shouldCreateContextFromTag_data(); } void shouldUpdateContextFromTag() { // GIVEN // Data... QFETCH(QByteArray, type); QFETCH(QString, name); QFETCH(Akonadi::Tag::Id, tagId); // ... stored as an Akonadi Tag Akonadi::Tag tag(name); tag.setType(type); tag.setId(tagId); // WHEN Akonadi::Serializer serializer; Domain::Context::Ptr context(new Domain::Context); serializer.updateContextFromTag(context, tag); // THEN QCOMPARE(context->name(), tag.name()); QCOMPARE(context->property("tagId").toLongLong(), tag.id()); } void shouldNotUpdateContextFromWrongTagType() { // GIVEN Akonadi::Tag originalTag(QStringLiteral("Context42")); originalTag.setType(Akonadi::Serializer::contextTagType()); originalTag.setId(42); Akonadi::Serializer serializer; Domain::Context::Ptr context = serializer.createContextFromTag(originalTag); // WHEN Akonadi::Tag wrongTag(QStringLiteral("WrongContext42")); wrongTag.setType(QByteArray("wrongTypeTag")); serializer.updateContextFromTag(context, wrongTag); // THEN QCOMPARE(context->name(), originalTag.name()); QCOMPARE(context->property("tagId").toLongLong(), originalTag.id()); } void shouldVerifyIfAnItemIsAContextChild_data() { QTest::addColumn("context"); QTest::addColumn("item"); QTest::addColumn("isChild"); // Create a context auto context = Domain::Context::Ptr::create(); context->setProperty("tagId", qint64(43)); Akonadi::Tag tag(Akonadi::Tag::Id(43)); Akonadi::Item unrelatedItem; QTest::newRow("Unrelated item") << context << unrelatedItem << false; Akonadi::Item relatedItem; relatedItem.setTag(tag); QTest::newRow("Related item") << context << relatedItem << true; auto invalidContext = Domain::Context::Ptr::create(); QTest::newRow("Invalid context") << invalidContext << relatedItem << false; Akonadi::Item invalidItem; QTest::newRow("Invalid Item") << context << invalidItem << false; } void shouldVerifyIfAnItemIsAContextChild() { // GIVEN QFETCH(Domain::Context::Ptr, context); QFETCH(Akonadi::Item, item); QFETCH(bool, isChild); // WHEN Akonadi::Serializer serializer; bool value = serializer.isContextChild(context, item); // THEN QCOMPARE(value, isChild); } void shouldCheckIfAnItemHasContextsOrTags_data() { QTest::addColumn("item"); QTest::addColumn("contextsExpected"); QTest::addColumn("tagsExpected"); Akonadi::Tag unrelatedTag(QStringLiteral("Foo")); unrelatedTag.setType("unrelated"); Akonadi::Tag contextTag(QStringLiteral("Bar")); contextTag.setType(Akonadi::Serializer::contextTagType()); Akonadi::Tag akonadiTag(QStringLiteral("Baz")); akonadiTag.setType(Akonadi::Tag::PLAIN); Akonadi::Item item; QTest::newRow("no tags") << item << false << false; item.setTags({ unrelatedTag }); QTest::newRow("unrelated tags") << item << false << false; item.setTags({ unrelatedTag, contextTag }); QTest::newRow("has contexts") << item << true << false; item.setTags({ unrelatedTag, akonadiTag }); QTest::newRow("has tags") << item << false << true; item.setTags({ unrelatedTag, contextTag, akonadiTag }); QTest::newRow("has both") << item << true << true; } void shouldCheckIfAnItemHasContextsOrTags() { // GIVEN QFETCH(Akonadi::Item, item); QFETCH(bool, contextsExpected); QFETCH(bool, tagsExpected); Akonadi::Serializer serializer; // WHEN const bool hasContexts = serializer.hasContextTags(item); const bool hasTags = serializer.hasAkonadiTags(item); // THEN QCOMPARE(hasContexts, contextsExpected); QCOMPARE(hasTags, tagsExpected); } void shouldCreateTagFromContext_data() { QTest::addColumn("name"); QTest::addColumn("tagId"); QTest::addColumn("tagGid"); QString nameInternet = QStringLiteral("Internet"); QTest::newRow("nominal case") << QString(nameInternet) << qint64(42) << nameInternet.toLatin1(); QTest::newRow("null name case") << QString() << qint64(42) << QByteArray(); QTest::newRow("null tagId case") << QString(nameInternet)<< qint64(-1) << nameInternet.toLatin1(); QTest::newRow("totally null context case") << QString() << qint64(-1) << QByteArray(); } void shouldCreateTagFromContext() { // GIVEN QFETCH(QString, name); QFETCH(qint64, tagId); QFETCH(QByteArray, tagGid); // WHEN auto context = Domain::Context::Ptr::create(); context->setProperty("tagId", tagId); context->setName(name); Akonadi::Serializer serializer; Akonadi::Tag tag = serializer.createTagFromContext(context); // THEN QCOMPARE(tag.name(), name); QCOMPARE(tag.isValid(), tagId > 0); if (tagId > 0) { QCOMPARE(tag.id(), tagId); QCOMPARE(tag.gid(), tagGid); QCOMPARE(tag.type(), Akonadi::SerializerInterface::contextTagType()); } } void shouldCreateTagFromAkonadiTag_data() { QTest::addColumn("name"); QTest::addColumn("tagId"); QTest::addColumn("type"); QString tagName = QStringLiteral("Optional"); QByteArray plainType = Akonadi::Tag::PLAIN; QTest::newRow("nominal case") << tagName << qint64(42) << plainType; QTest::newRow("null name case") << QString() << qint64(42) << plainType; QTest::newRow("null tagId case") << tagName << qint64(-1) << plainType; QTest::newRow("totally null tag case") << QString() << qint64(-1) << plainType; } void shouldCreateTagFromAkonadiTag() { // GIVEN QFETCH(QString, name); QFETCH(qint64, tagId); QFETCH(QByteArray, type); auto akonadiTag = Akonadi::Tag(); akonadiTag.setName(name); akonadiTag.setId(tagId); akonadiTag.setType(type); // WHEN Akonadi::Serializer serializer; Domain::Tag::Ptr resultTag = serializer.createTagFromAkonadiTag(akonadiTag); // THEN QCOMPARE(resultTag->name(), akonadiTag.name()); QCOMPARE(resultTag->property("tagId").toLongLong(), akonadiTag.id()); } void shouldUpdateTagFromAkonadiTag_data() { shouldCreateTagFromAkonadiTag_data(); } void shouldUpdateTagFromAkonadiTag() { // GIVEN QFETCH(QString, name); QFETCH(qint64, tagId); QFETCH(QByteArray, type); // ... stored as an Akonadi Tag Akonadi::Tag akonadiTag(name); akonadiTag.setId(tagId); akonadiTag.setType(type); // WHEN Akonadi::Serializer serializer; auto tag = Domain::Tag::Ptr::create(); tag->setName(QStringLiteral("tag42")); serializer.updateTagFromAkonadiTag(tag, akonadiTag); // THEN QCOMPARE(tag->name(), akonadiTag.name()); QCOMPARE(tag->property("tagId").toLongLong(), akonadiTag.id()); } void shouldCreateAkonadiTagFromTag_data() { // GIVEN QTest::addColumn("name"); QTest::addColumn("tagId"); QTest::addColumn("tagGid"); const QByteArray namePhilo = "Philosophy"; QTest::newRow("nominal case") << QString(namePhilo) << qint64(42) << namePhilo; QTest::newRow("null name case") << QString() << qint64(42) << QByteArray(); QTest::newRow("null tagId case") << QString(namePhilo) << qint64(-1) << namePhilo; QTest::newRow("totally null tag case") << QString() << qint64(-1) << QByteArray(); } void shouldCreateAkonadiTagFromTag() { // GIVEN QFETCH(QString, name); QFETCH(qint64, tagId); QFETCH(QByteArray, tagGid); // WHEN auto tag = Domain::Tag::Ptr::create(); tag->setProperty("tagId", tagId); tag->setName(name); Akonadi::Serializer serializer; Akonadi::Tag akonadiTag = serializer.createAkonadiTagFromTag(tag); // THEN QCOMPARE(akonadiTag.name(), name); QCOMPARE(akonadiTag.isValid(), tagId > 0); if (tagId > 0) { QCOMPARE(akonadiTag.id(), tagId); QCOMPARE(akonadiTag.gid(), tagGid); QCOMPARE(akonadiTag.type(), QByteArray(Akonadi::Tag::PLAIN)); } } void shouldVerifyIfAnItemIsATagChild_data() { QTest::addColumn("tag"); QTest::addColumn("item"); QTest::addColumn("isChild"); // Create a Tag auto tag = Domain::Tag::Ptr::create(); tag->setProperty("tagId", qint64(43)); Akonadi::Tag akonadiTag(Akonadi::Tag::Id(43)); Akonadi::Item unrelatedItem; QTest::newRow("Unrelated item") << tag << unrelatedItem << false; Akonadi::Item relatedItem; relatedItem.setTag(akonadiTag); QTest::newRow("Related item") << tag << relatedItem << true; auto invalidTag = Domain::Tag::Ptr::create(); QTest::newRow("Invalid Tag") << invalidTag << relatedItem << false; Akonadi::Item invalidItem; QTest::newRow("Invalid Item") << tag << invalidItem << false; QTest::newRow("both invalid") << invalidTag << invalidItem << false; } void shouldVerifyIfAnItemIsATagChild() { // GIVEN QFETCH(Domain::Tag::Ptr, tag); QFETCH(Akonadi::Item, item); QFETCH(bool, isChild); // WHEN Akonadi::Serializer serializer; bool value = serializer.isTagChild(tag, item); // THEN QCOMPARE(value, isChild); } // Investigation into how to differentiate all-day events from events with time, // using QDateTime only. Doesn't seem to be possible. void noWayToHaveQDateTimeWithoutTime() { // GIVEN a QDateTime without time information QDateTime dateOnly(QDate(2016, 6, 12), QTime(-1, -1, -1)); // THEN we can't detect that there was no time information, i.e. all day event QVERIFY(dateOnly.time().isValid()); // I wish this was "!" QVERIFY(!dateOnly.time().isNull()); // got converted to midnight localtime by QDateTime // This doesn't help, QDateTime converts "null time" to midnight. dateOnly.setTime(QTime()); QVERIFY(dateOnly.time().isValid()); // same as above QVERIFY(!dateOnly.time().isNull()); // same as above // GIVEN a QDateTime at midnight QDateTime atMidnight(QDate(2016, 6, 12), QTime(0, 0, 0)); // THEN we can detect that a time information was present QVERIFY(atMidnight.time().isValid()); QVERIFY(!atMidnight.time().isNull()); #if 0 // GIVEN a KDateTime without time information KDateTime kdOnly(QDate(2016, 6, 12)); // THEN we can detect that there was no time information, i.e. all day event QVERIFY(kdOnly.isDateOnly()); #endif } }; ZANSHIN_TEST_MAIN(AkonadiSerializerTest) #include "akonadiserializertest.moc" diff --git a/tests/units/utils/datetimetest.cpp b/tests/units/utils/datetimetest.cpp index 7e4df5ec..c97b9827 100644 --- a/tests/units/utils/datetimetest.cpp +++ b/tests/units/utils/datetimetest.cpp @@ -1,113 +1,75 @@ /* This file is part of Zanshin Copyright 2015 Theo Vaucher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "utils/datetime.h" using namespace Utils; class DateTimeTest : public QObject { Q_OBJECT private slots: - void shouldNotOverrideCurrentDateTime() - { - // GIVEN - const auto todayDate = QDateTime::currentDateTime(); - - // WHEN - const QDateTime zanshinDate = DateTime::currentDateTime(); - - // THEN - QCOMPARE(zanshinDate.date(), todayDate.date()); - } - - void shouldOverrideCurrentDateTime() - { - // GIVEN - const QByteArray dateExpected = "2015-03-10"; - qputenv("ZANSHIN_OVERRIDE_DATETIME", dateExpected); - - // WHEN - const QDateTime zanshinDate = DateTime::currentDateTime(); - - // THEN - QCOMPARE(zanshinDate.date(), QDateTime::fromString(QString::fromLocal8Bit(dateExpected), Qt::ISODate).date()); - } - - void shouldNotOverrideCurrentDateTimeWhenInvalidDate() - { - // GIVEN - const QByteArray dateExpected = "Invalid!"; - qputenv("ZANSHIN_OVERRIDE_DATETIME", dateExpected); - - // WHEN - const QDateTime zanshinDate = DateTime::currentDateTime(); - - // THEN - QCOMPARE(zanshinDate.date(), QDateTime::currentDateTime().date()); - } - void shouldNotOverrideCurrentDate() { // GIVEN const auto todayDate = QDate::currentDate(); // WHEN const QDate zanshinDate = DateTime::currentDate(); // THEN QCOMPARE(zanshinDate, todayDate); } void shouldOverrideCurrentDate() { // GIVEN const QByteArray dateExpected = "2015-03-10"; qputenv("ZANSHIN_OVERRIDE_DATE", dateExpected); // WHEN const QDate zanshinDate = DateTime::currentDate(); // THEN QCOMPARE(zanshinDate, QDate(2015, 3, 10)); } void shouldNotOverrideCurrentDateWhenInvalidDate() { // GIVEN const QByteArray dateExpected = "Invalid!"; qputenv("ZANSHIN_OVERRIDE_DATE", dateExpected); // WHEN const QDate zanshinDate = DateTime::currentDate(); // THEN QCOMPARE(zanshinDate, QDate::currentDate()); } }; ZANSHIN_TEST_MAIN(DateTimeTest) #include "datetimetest.moc"