diff --git a/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp b/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp index 6839cd350..a8be22d32 100644 --- a/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp +++ b/agents/unifiedmailboxagent/autotests/unifiedmailboxmanagertest.cpp @@ -1,666 +1,666 @@ /* Copyright (C) 2018 Daniel Vrátil 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) any later version. 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "../unifiedmailboxmanager.h" #include "../unifiedmailbox.h" #include "../common.h" #include "../utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std::chrono; using namespace std::chrono_literals; namespace { #define AKVERIFY_RET(statement, ret) \ do {\ if (!QTest::qVerify(static_cast(statement), #statement, "", __FILE__, __LINE__))\ return ret;\ } while (false) #define AKCOMPARE_RET(actual, expected, ret) \ do {\ if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ return ret;\ } while (false) -exp::optional collectionForId(qint64 id) +stdx::optional collectionForId(qint64 id) { auto fetch = new Akonadi::CollectionFetchJob(Akonadi::Collection(id), Akonadi::CollectionFetchJob::Base); fetch->fetchScope().fetchAttribute(); - AKVERIFY_RET(fetch->exec(), exp::nullopt); + AKVERIFY_RET(fetch->exec(), stdx::nullopt); const auto cols = fetch->collections(); - AKCOMPARE_RET(cols.count(), 1, exp::nullopt); - AKVERIFY_RET(cols.first().isValid(), exp::nullopt); + AKCOMPARE_RET(cols.count(), 1, stdx::nullopt); + AKVERIFY_RET(cols.first().isValid(), stdx::nullopt); return cols.first(); } -exp::optional collectionForRid(const QString &rid) +stdx::optional collectionForRid(const QString &rid) { auto fetch = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive); fetch->fetchScope().fetchAttribute(); fetch->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); - AKVERIFY_RET(fetch->exec(), exp::nullopt); + AKVERIFY_RET(fetch->exec(), stdx::nullopt); const auto cols = fetch->collections(); auto colIt = std::find_if(cols.cbegin(), cols.cend(), [&rid](const Akonadi::Collection &col) { return col.remoteId() == rid; }); - AKVERIFY_RET(colIt != cols.cend(), exp::nullopt); + AKVERIFY_RET(colIt != cols.cend(), stdx::nullopt); return *colIt; } std::unique_ptr createUnifiedMailbox(const QString &id, const QString &name, const QStringList &sourceRids) { auto mailbox = std::make_unique(); mailbox->setId(id); mailbox->setName(name); mailbox->setIcon(QStringLiteral("dummy-icon")); for (const auto &srcRid : sourceRids) { const auto srcCol = collectionForRid(srcRid); AKVERIFY_RET(srcCol, {}); mailbox->addSourceCollection(srcCol->id()); } return mailbox; } class EntityDeleter { public: ~EntityDeleter() { while (!cols.isEmpty()) { if (!(new Akonadi::CollectionDeleteJob(cols.takeFirst()))->exec()) { QFAIL("Failed to cleanup collection!"); } } while (!items.isEmpty()) { if (!(new Akonadi::ItemDeleteJob(items.takeFirst()))->exec()) { QFAIL("Failed to cleanup Item"); } } } EntityDeleter &operator<<(const Akonadi::Collection &col) { cols.push_back(col); return *this; } EntityDeleter &operator<<(const Akonadi::Item &item) { items.push_back(item); return *this; } private: Akonadi::Collection::List cols; Akonadi::Item::List items; }; -exp::optional createCollection(const QString &name, const Akonadi::Collection &parent, EntityDeleter &deleter) +stdx::optional createCollection(const QString &name, const Akonadi::Collection &parent, EntityDeleter &deleter) { Akonadi::Collection col; col.setName(name); col.setParentCollection(parent); col.setVirtual(true); auto createCol = new Akonadi::CollectionCreateJob(col); - AKVERIFY_RET(createCol->exec(), exp::nullopt); + AKVERIFY_RET(createCol->exec(), stdx::nullopt); col = createCol->collection(); if (col.isValid()) { deleter << col; return col; } - return exp::nullopt; + return stdx::nullopt; } } // namespace class UnifiedMailboxManagerTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { AkonadiTest::checkTestIsIsolated(); } void testCreateDefaultBoxes() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); const auto boxesGroup = kcfg->group("UnifiedMailboxes"); UnifiedMailboxManager manager(kcfg); // Make sure the config is empty QVERIFY(boxesGroup.groupList().empty()); // Call loadBoxes and wait for it to finish bool loadingDone = false; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Check all the three boxes were created bool success; const auto verifyBox = [&manager, &success](const QString &id, int numSources) { success = false; auto boxIt = std::find_if(manager.begin(), manager.end(), [&id](const UnifiedMailboxManager::Entry &e) { return e.second->id() == id; }); QVERIFY(boxIt != manager.end()); const auto &box = boxIt->second; const auto sourceCollections = box->sourceCollections(); QCOMPARE(sourceCollections.size(), numSources); for (auto source : sourceCollections) { auto col = collectionForId(source); QVERIFY(col); QVERIFY(col->hasAttribute()); QCOMPARE(col->attribute()->collectionType(), id.toLatin1()); } success = true; }; verifyBox(Common::InboxBoxId, 2); QVERIFY(success); verifyBox(Common::SentBoxId, 2); QVERIFY(success); verifyBox(Common::DraftsBoxId, 1); QVERIFY(success); // Check boxes were written to config - we don't check the contents of // the group, testing UnifiedMailbox serialization is done in other tests QVERIFY(boxesGroup.groupList().size() == 3); QVERIFY(boxesGroup.hasGroup(Common::InboxBoxId)); QVERIFY(boxesGroup.hasGroup(Common::SentBoxId)); QVERIFY(boxesGroup.hasGroup(Common::DraftsBoxId)); } void testAddingNewMailbox() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); const auto boxesGroup = kcfg->group("UnifiedMailboxes"); UnifiedMailboxManager manager(kcfg); Akonadi::ChangeRecorder &recorder = manager.changeRecorder(); // Nothing should be monitored as of now QVERIFY(recorder.collectionsMonitored().isEmpty()); // Create a new unified mailbox and passit to the manager auto mailbox = createUnifiedMailbox(QStringLiteral("Test1"), QStringLiteral("Test 1"), { QStringLiteral("res1_inbox") }); QVERIFY(mailbox); const auto sourceCol = mailbox->sourceCollections().toList().first(); manager.insertBox(std::move(mailbox)); // Now manager should have one unified mailbox and monitor all of its // source collections QCOMPARE(std::distance(manager.begin(), manager.end()), 1); QCOMPARE(recorder.collectionsMonitored().size(), 1); QCOMPARE(recorder.collectionsMonitored().at(0).id(), sourceCol); QVERIFY(manager.unifiedMailboxForSource(sourceCol) != nullptr); // But nothing should bne written in the config yet QVERIFY(!boxesGroup.groupList().contains(QLatin1String("Test1"))); // Now write to the config file and check it's actually there - we don't test // the contents of the group, UnifiedMailbox serialization has its own test manager.saveBoxes(); QVERIFY(boxesGroup.hasGroup(QLatin1String("Test1"))); } void testRemoveMailbox() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); auto boxesGroup = kcfg->group("UnifiedMailboxes"); auto mailbox = createUnifiedMailbox(QStringLiteral("Test1"), QStringLiteral("Test 1"), { QStringLiteral("res1_foo"), QStringLiteral("res2_foo") }); QVERIFY(mailbox); auto group = boxesGroup.group(mailbox->id()); mailbox->save(group); UnifiedMailboxManager manager(kcfg); Akonadi::ChangeRecorder &recorder = manager.changeRecorder(); // Nothing should be monitored right now QVERIFY(recorder.collectionsMonitored().isEmpty()); // Load the config bool loadingDone = false; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now the box should be loaded and its source collections monitored QCOMPARE(std::distance(manager.begin(), manager.end()), 1); QCOMPARE(recorder.collectionsMonitored().count(), 2); const auto srcCols = mailbox->sourceCollections().toList(); QCOMPARE(srcCols.count(), 2); QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[0]))); QVERIFY(recorder.collectionsMonitored().contains(Akonadi::Collection(srcCols[1]))); // Now remove the box manager.removeBox(mailbox->id()); // Manager should have no boxes and no source collections should be monitored QVERIFY(manager.begin() == manager.end()); QVERIFY(recorder.collectionsMonitored().isEmpty()); // But the box still exists in the config QVERIFY(boxesGroup.hasGroup(mailbox->id())); // Save the new state manager.saveBoxes(); // And now it should be gone from the config file as well QVERIFY(!boxesGroup.hasGroup(mailbox->id())); } void testDiscoverBoxCollections() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); auto boxesGroup = kcfg->group("UnifiedMailboxes"); UnifiedMailboxManager manager(kcfg); EntityDeleter deleter; const auto inbox = createUnifiedMailbox(Common::InboxBoxId, QStringLiteral("Inbox"), { QStringLiteral("res1_inbox"), QStringLiteral("res2_inbox") }); auto boxGroup = boxesGroup.group(inbox->id()); inbox->save(boxGroup); const auto sentBox = createUnifiedMailbox(Common::SentBoxId, QStringLiteral("Sent"), { QStringLiteral("res1_sent"), QStringLiteral("res2_sent") }); boxGroup = boxesGroup.group(sentBox->id()); sentBox->save(boxGroup); const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol.value(), deleter); QVERIFY(inboxBoxCol); const auto sentBoxCol = createCollection(Common::SentBoxId, parentCol.value(), deleter); QVERIFY(sentBoxCol); // Load from config bool loadingDone = false; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now the boxes should be loaded and we should be able to access them // by IDs of collections that represent them. The collections should also // be set for each box. auto box = manager.unifiedMailboxFromCollection(inboxBoxCol.value()); QVERIFY(box != nullptr); QCOMPARE(box->collectionId(), inboxBoxCol->id()); box = manager.unifiedMailboxFromCollection(sentBoxCol.value()); QVERIFY(box != nullptr); QCOMPARE(box->collectionId(), sentBoxCol->id()); } void testItemAddedToSourceCollection() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); UnifiedMailboxManager manager(kcfg); EntityDeleter deleter; const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol.value(), deleter); QVERIFY(inboxBoxCol); // Load boxes - config is empty so this will create the default Boxes and // assign the Inboxes from Knuts to it bool loadingDone = true; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now discover collections for the created boxes loadingDone = false; manager.discoverBoxCollections([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Get one of the source collections for Inbox const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); QVERIFY(inboxSourceCol); // Setup up a monitor to to be notified when an item gets linked into // the unified mailbox collection Akonadi::Monitor monitor; monitor.setCollectionMonitored(inboxBoxCol.value()); QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); // Add a new Item into the source collection Akonadi::Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setParentCollection(inboxSourceCol.value()); item.setPayload(QByteArray{"Hello world!"}); auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol.value(), this); AKVERIFYEXEC(createItem); item = createItem->item(); deleter << item; // Then wait for ItemLinked notification as the Manager has linked the new Item // to the dest collection QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); const auto linkedItems = itemLinkedSignalSpy.at(0).at(0).value(); QCOMPARE(linkedItems.size(), 1); QCOMPARE(linkedItems.at(0), item); const auto linkedCol = itemLinkedSignalSpy.at(0).at(1).value(); QCOMPARE(linkedCol, inboxBoxCol); } void testItemMovedFromSourceCollection() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); UnifiedMailboxManager manager(kcfg); EntityDeleter deleter; const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol.value(), deleter); QVERIFY(inboxBoxCol); // Load boxes - config is empty so this will create the default Boxes and // assign the Inboxes from Knuts to it bool loadingDone = true; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now discover collections for the created boxes loadingDone = false; manager.discoverBoxCollections([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Get one of the source collections for Inbox const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); QVERIFY(inboxSourceCol); // Setup up a monitor to to be notified when an item gets linked into // the unified mailbox collection Akonadi::Monitor monitor; monitor.setCollectionMonitored(inboxBoxCol.value()); QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); QSignalSpy itemUnlinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsUnlinked); QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); // Add a new Item into the source collection Akonadi::Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setParentCollection(inboxSourceCol.value()); item.setPayload(QByteArray{"Hello world!"}); auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol.value(), this); AKVERIFYEXEC(createItem); item = createItem->item(); deleter << item; // Waity for the item to be linked QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); const auto destinationCol = collectionForRid(QStringLiteral("res1_foo")); QVERIFY(destinationCol); // Now move the Item to an unmonitored collection auto move = new Akonadi::ItemMoveJob(item, destinationCol.value(), this); AKVERIFYEXEC(move); QTRY_COMPARE(itemUnlinkedSignalSpy.size(), 1); const auto unlinkedItems = itemUnlinkedSignalSpy.at(0).at(0).value(); QCOMPARE(unlinkedItems.size(), 1); QCOMPARE(unlinkedItems.first(), item); const auto unlinkedCol = itemUnlinkedSignalSpy.at(0).at(1).value(); QCOMPARE(unlinkedCol, inboxBoxCol); } void testItemMovedBetweenSourceCollections() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); UnifiedMailboxManager manager(kcfg); EntityDeleter deleter; const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol.value(), deleter); QVERIFY(inboxBoxCol); const auto draftsBoxCol = createCollection(Common::DraftsBoxId, parentCol.value(), deleter); QVERIFY(draftsBoxCol); // Load boxes - config is empty so this will create the default Boxes and // assign the Inboxes from Knuts to it bool loadingDone = true; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now discover collections for the created boxes loadingDone = false; manager.discoverBoxCollections([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Get one of the source collections for Inbox and Drafts const auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); QVERIFY(inboxSourceCol); const auto draftsSourceCol = collectionForRid(QStringLiteral("res1_drafts")); QVERIFY(draftsSourceCol); // Setup up a monitor to to be notified when an item gets linked into // the unified mailbox collection Akonadi::Monitor monitor; monitor.setCollectionMonitored(inboxBoxCol.value()); monitor.setCollectionMonitored(draftsBoxCol.value()); QSignalSpy itemLinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsLinked); QSignalSpy itemUnlinkedSignalSpy(&monitor, &Akonadi::Monitor::itemsUnlinked); QVERIFY(QSignalSpy(&monitor, &Akonadi::Monitor::monitorReady).wait()); // Add a new Item into the source Inbox collection Akonadi::Item item; item.setMimeType(QStringLiteral("application/octet-stream")); item.setParentCollection(inboxSourceCol.value()); item.setPayload(QByteArray{"Hello world!"}); auto createItem = new Akonadi::ItemCreateJob(item, inboxSourceCol.value(), this); AKVERIFYEXEC(createItem); item = createItem->item(); deleter << item; // Waity for the item to be linked QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); itemLinkedSignalSpy.clear(); // Now move the Item to another Unified mailbox's source collection auto move = new Akonadi::ItemMoveJob(item, draftsSourceCol.value(), this); AKVERIFYEXEC(move); QTRY_COMPARE(itemUnlinkedSignalSpy.size(), 1); const auto unlinkedItems = itemUnlinkedSignalSpy.at(0).at(0).value(); QCOMPARE(unlinkedItems.size(), 1); QCOMPARE(unlinkedItems.first(), item); const auto unlinkedCol = itemUnlinkedSignalSpy.at(0).at(1).value(); QCOMPARE(unlinkedCol, inboxBoxCol); QTRY_COMPARE(itemLinkedSignalSpy.size(), 1); const auto linkedItems = itemLinkedSignalSpy.at(0).at(0).value(); QCOMPARE(linkedItems.size(), 1); QCOMPARE(linkedItems.first(), item); const auto linkedCol = itemLinkedSignalSpy.at(0).at(1).value(); QCOMPARE(linkedCol, draftsBoxCol); } void testSourceCollectionRemoved() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); UnifiedMailboxManager manager(kcfg); auto &changeRecorder = manager.changeRecorder(); QSignalSpy crRemovedSpy(&changeRecorder, &Akonadi::Monitor::collectionRemoved); EntityDeleter deleter; const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto inboxBoxCol = createCollection(Common::InboxBoxId, parentCol.value(), deleter); QVERIFY(inboxBoxCol); // Load boxes - config is empty so this will create the default Boxes and // assign the Inboxes from Knuts to it bool loadingDone = true; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now discover collections for the created boxes loadingDone = false; manager.discoverBoxCollections([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); auto inboxSourceCol = collectionForRid(QStringLiteral("res1_inbox")); QVERIFY(inboxSourceCol); auto delJob = new Akonadi::CollectionDeleteJob(inboxSourceCol.value(), this); AKVERIFYEXEC(delJob); // Wait for the change recorder to be notified QVERIFY(crRemovedSpy.wait()); crRemovedSpy.clear(); // and then wait a little bit more to give the Manager time to process the event QTest::qWait(0); auto inboxBox = manager.unifiedMailboxFromCollection(inboxBoxCol.value()); QVERIFY(inboxBox); QVERIFY(!inboxBox->sourceCollections().contains(inboxSourceCol->id())); QVERIFY(!changeRecorder.collectionsMonitored().contains(inboxSourceCol.value())); QVERIFY(!manager.unifiedMailboxForSource(inboxSourceCol->id())); // Lets removed the other source collection now, that should remove the unified box completely inboxSourceCol = collectionForRid(QStringLiteral("res2_inbox")); QVERIFY(inboxSourceCol); delJob = new Akonadi::CollectionDeleteJob(inboxSourceCol.value(), this); AKVERIFYEXEC(delJob); // Wait for the change recorder once again QVERIFY(crRemovedSpy.wait()); QTest::qWait(0); QVERIFY(!manager.unifiedMailboxFromCollection(inboxBoxCol.value())); QVERIFY(!changeRecorder.collectionsMonitored().contains(inboxSourceCol.value())); QVERIFY(!manager.unifiedMailboxForSource(inboxSourceCol->id())); } void testSpecialSourceCollectionCreated() { // TODO: this does not work yet: we only monitor collections that we are // intersted in, we don't monitor other collections } void testSpecialSourceCollectionDemoted() { // Setup auto kcfg = KSharedConfig::openConfig(QString::fromUtf8(QTest::currentTestFunction())); UnifiedMailboxManager manager(kcfg); auto &changeRecorder = manager.changeRecorder(); QSignalSpy crChangedSpy(&changeRecorder, qOverload &>(&Akonadi::Monitor::collectionChanged)); EntityDeleter deleter; const auto parentCol = collectionForRid(Common::AgentIdentifier); QVERIFY(parentCol); const auto sentBoxCol = createCollection(Common::SentBoxId, parentCol.value(), deleter); QVERIFY(sentBoxCol); // Load boxes - config is empty so this will create the default Boxes and // assign the Inboxes from Knuts to it bool loadingDone = true; manager.loadBoxes([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); // Now discover collections for the created boxes loadingDone = false; manager.discoverBoxCollections([&loadingDone]() { loadingDone = true; }); QTRY_VERIFY_WITH_TIMEOUT(loadingDone, milliseconds(10s).count()); auto sentSourceCol = collectionForRid(QStringLiteral("res1_sent")); QVERIFY(sentSourceCol); sentSourceCol->removeAttribute(); auto modify = new Akonadi::CollectionModifyJob(sentSourceCol.value(), this); AKVERIFYEXEC(modify); // Wait for the change recorder to be notified QVERIFY(crChangedSpy.wait()); crChangedSpy.clear(); // and then wait a little bit more to give the Manager time to process the event QTest::qWait(0); auto sourceBox = manager.unifiedMailboxFromCollection(sentBoxCol.value()); QVERIFY(sourceBox); QVERIFY(!sourceBox->sourceCollections().contains(sentSourceCol->id())); QVERIFY(!changeRecorder.collectionsMonitored().contains(sentSourceCol.value())); QVERIFY(!manager.unifiedMailboxForSource(sentSourceCol->id())); // Lets demote the other source collection now, that should remove the unified box completely sentSourceCol = collectionForRid(QStringLiteral("res2_sent")); QVERIFY(sentSourceCol); sentSourceCol->attribute()->setCollectionType("drafts"); modify = new Akonadi::CollectionModifyJob(sentSourceCol.value(), this); AKVERIFYEXEC(modify); // Wait for the change recorder once again QVERIFY(crChangedSpy.wait()); QTest::qWait(0); // There's no more Sent unified box QVERIFY(!manager.unifiedMailboxFromCollection(sentBoxCol.value())); // The collection is still monitored: it belongs to the Drafts special box now! QVERIFY(changeRecorder.collectionsMonitored().contains(sentSourceCol.value())); QVERIFY(manager.unifiedMailboxForSource(sentSourceCol->id())); } }; QTEST_AKONADIMAIN(UnifiedMailboxManagerTest) #include "unifiedmailboxmanagertest.moc" diff --git a/agents/unifiedmailboxagent/unifiedmailbox.cpp b/agents/unifiedmailboxagent/unifiedmailbox.cpp index 29dae0a6c..7649facf9 100644 --- a/agents/unifiedmailboxagent/unifiedmailbox.cpp +++ b/agents/unifiedmailboxagent/unifiedmailbox.cpp @@ -1,155 +1,155 @@ /* Copyright (C) 2018 Daniel Vrátil 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) any later version. 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "unifiedmailbox.h" #include "unifiedmailboxmanager.h" #include "utils.h" #include "common.h" #include bool UnifiedMailbox::operator==(const UnifiedMailbox &other) const { return mId == other.mId; } void UnifiedMailbox::load(const KConfigGroup &group) { mId = group.name(); mName = group.readEntry("name"); mIcon = group.readEntry("icon", QStringLiteral("folder-mail")); mSources = listToSet(group.readEntry("sources", QList{})); // This is not authoritative, we will do collection discovery anyway mCollectionId = group.readEntry("collectionId", -1ll); } void UnifiedMailbox::save(KConfigGroup& group) const { group.writeEntry("name", mName); group.writeEntry("icon", mIcon); group.writeEntry("sources", setToList(mSources)); // just for cacheing, we will do collection discovery on next start anyway if (mCollectionId) { group.writeEntry("collectionId", *mCollectionId); } else { group.deleteEntry("collectionId"); } } bool UnifiedMailbox::isSpecial() const { return mId == Common::InboxBoxId || mId == Common::SentBoxId || mId == Common::DraftsBoxId; } void UnifiedMailbox::setCollectionId(qint64 id) { mCollectionId = id; } -exp::optional UnifiedMailbox::collectionId() const +stdx::optional UnifiedMailbox::collectionId() const { return mCollectionId; } void UnifiedMailbox::setId(const QString &id) { mId = id; } QString UnifiedMailbox::id() const { return mId; } void UnifiedMailbox::setName(const QString &name) { mName = name; } QString UnifiedMailbox::name() const { return mName; } void UnifiedMailbox::setIcon(const QString &icon) { mIcon = icon; } QString UnifiedMailbox::icon() const { return mIcon; } void UnifiedMailbox::addSourceCollection(qint64 source) { mSources.insert(source); if (mManager) { mManager->mMonitor.setCollectionMonitored(Akonadi::Collection{source}); mManager->mSourceToBoxMap.insert({ source, this }); } } void UnifiedMailbox::removeSourceCollection(qint64 source) { mSources.remove(source); if (mManager) { mManager->mMonitor.setCollectionMonitored(Akonadi::Collection{source}, false); mManager->mSourceToBoxMap.erase(source); } } void UnifiedMailbox::setSourceCollections(const QSet &sources) { while (!mSources.empty()) { removeSourceCollection(*mSources.begin()); } for (auto source : sources) { addSourceCollection(source); } } QSet UnifiedMailbox::sourceCollections() const { return mSources; } void UnifiedMailbox::attachManager(UnifiedMailboxManager *manager) { if (mManager != manager) { if (manager) { // Force that we start monitoring all the collections for (auto source : mSources) { manager->mMonitor.setCollectionMonitored(Akonadi::Collection{source}); manager->mSourceToBoxMap.insert({ source, this }); } } else { for (auto source : mSources) { mManager->mMonitor.setCollectionMonitored(Akonadi::Collection{source}, false); mManager->mSourceToBoxMap.erase(source); } } mManager = manager; } } diff --git a/agents/unifiedmailboxagent/unifiedmailbox.h b/agents/unifiedmailboxagent/unifiedmailbox.h index 39cd38d83..102e56ce0 100644 --- a/agents/unifiedmailboxagent/unifiedmailbox.h +++ b/agents/unifiedmailboxagent/unifiedmailbox.h @@ -1,82 +1,82 @@ /* Copyright (C) 2018 Daniel Vrátil 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) any later version. 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UNIFIEDMAILBOX_H #define UNIFIEDMAILBOX_H #include #include #include #include "utils.h" class KConfigGroup; class UnifiedMailboxManager; class UnifiedMailbox { friend class UnifiedMailboxManager; public: UnifiedMailbox() = default; UnifiedMailbox(UnifiedMailbox &&) = default; UnifiedMailbox &operator=(UnifiedMailbox &&) = default; UnifiedMailbox(const UnifiedMailbox &) = delete; UnifiedMailbox &operator=(const UnifiedMailbox &) = delete; /** Compares two boxes by their ID **/ bool operator==(const UnifiedMailbox &other) const; void save(KConfigGroup &group) const; void load(const KConfigGroup &group); bool isSpecial() const; - exp::optional collectionId() const; + stdx::optional collectionId() const; void setCollectionId(qint64 id); QString id() const; void setId(const QString &id); QString name() const; void setName(const QString &name); QString icon() const; void setIcon(const QString &icon); void addSourceCollection(qint64 source); void removeSourceCollection(qint64 source); void setSourceCollections(const QSet &sources); QSet sourceCollections() const; private: void attachManager(UnifiedMailboxManager *manager); - exp::optional mCollectionId; + stdx::optional mCollectionId; QString mId; QString mName; QString mIcon; QSet mSources; UnifiedMailboxManager *mManager = nullptr; }; Q_DECLARE_METATYPE(UnifiedMailbox*) #endif diff --git a/agents/unifiedmailboxagent/utils.h b/agents/unifiedmailboxagent/utils.h index e4f6c687f..85daf3347 100644 --- a/agents/unifiedmailboxagent/utils.h +++ b/agents/unifiedmailboxagent/utils.h @@ -1,72 +1,72 @@ /* Copyright (C) 2018 Daniel Vrátil 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) any later version. 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UTILS_H_ #define UTILS_H_ #include #include #include #include -namespace exp { +namespace stdx { // Injects content of std::experimental namespace into "exp" namespace. // C++ is magical. using namespace std::experimental; } template inline QList setToList(QSet &&set) { QList rv; rv.reserve(set.size()); std::copy(set.cbegin(), set.cend(), std::back_inserter(rv)); return rv; } template inline QList setToList(const QSet &set) { QList rv; rv.reserve(set.size()); std::copy(set.cbegin(), set.cend(), std::back_inserter(rv)); return rv; } template inline QSet listToSet(QList &&list) { QSet rv; rv.reserve(list.size()); for (auto t : list) { rv.insert(std::move(t)); } return rv; } namespace std { template<> struct hash { inline size_t operator()(const QString &str) const { return qHash(str); } }; } #endif