File indexing completed on 2024-11-10 04:40:09

0001 /*
0002     SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "collectionjobtest.h"
0008 
0009 #include <sys/types.h>
0010 
0011 #include "qtest_akonadi.h"
0012 #include "testattribute.h"
0013 
0014 #include "agentinstance.h"
0015 #include "agentmanager.h"
0016 #include "attributefactory.h"
0017 #include "cachepolicy.h"
0018 #include "collection.h"
0019 #include "collectioncreatejob.h"
0020 #include "collectiondeletejob.h"
0021 #include "collectionfetchjob.h"
0022 #include "collectionfetchscope.h"
0023 #include "collectionmodifyjob.h"
0024 #include "collectionstatistics.h"
0025 #include "collectionstatisticsjob.h"
0026 #include "collectionutils.h"
0027 #include "control.h"
0028 #include "item.h"
0029 #include "resourceselectjob_p.h"
0030 
0031 using namespace Akonadi;
0032 
0033 QTEST_AKONADIMAIN(CollectionJobTest)
0034 
0035 void CollectionJobTest::initTestCase()
0036 {
0037     qRegisterMetaType<Akonadi::Collection::List>();
0038     AttributeFactory::registerAttribute<TestAttribute>();
0039     AkonadiTest::checkTestIsIsolated();
0040     Control::start();
0041     AkonadiTest::setAllResourcesOffline();
0042 }
0043 
0044 static Collection findCol(const Collection::List &list, const QString &name)
0045 {
0046     for (const Collection &col : list) {
0047         if (col.name() == name) {
0048             return col;
0049         }
0050     }
0051     return Collection();
0052 }
0053 
0054 // list compare which ignores the order
0055 template<class T>
0056 static void compareLists(const QList<T> &l1, const QList<T> &l2)
0057 {
0058     QCOMPARE(l1.count(), l2.count());
0059     for (const T &entry : l1) {
0060         QVERIFY(l2.contains(entry));
0061     }
0062 }
0063 
0064 template<typename T>
0065 static T *extractAttribute(const QList<Attribute *> &attrs)
0066 {
0067     T dummy;
0068     for (Attribute *attr : attrs) {
0069         if (attr->type() == dummy.type()) {
0070             return dynamic_cast<T *>(attr);
0071         }
0072     }
0073     return 0;
0074 }
0075 
0076 static Collection::Id res1ColId = 6; // -1;
0077 static Collection::Id res2ColId = 7; //-1;
0078 static Collection::Id res3ColId = -1;
0079 static Collection::Id searchColId = -1;
0080 
0081 void CollectionJobTest::testTopLevelList()
0082 {
0083     // non-recursive top-level list
0084     auto job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
0085     AKVERIFYEXEC(job);
0086     Collection::List list = job->collections();
0087 
0088     // check if everything is there and has the correct types and attributes
0089     QCOMPARE(list.count(), 4);
0090     Collection col;
0091 
0092     col = findCol(list, QStringLiteral("res1"));
0093     QVERIFY(col.isValid());
0094     res1ColId = col.id(); // for the next test
0095     QVERIFY(res1ColId > 0);
0096     QVERIFY(CollectionUtils::isResource(col));
0097     QCOMPARE(col.parentCollection(), Collection::root());
0098     QCOMPARE(col.resource(), QStringLiteral("akonadi_knut_resource_0"));
0099 
0100     QVERIFY(findCol(list, QStringLiteral("res2")).isValid());
0101     res2ColId = findCol(list, QStringLiteral("res2")).id();
0102     QVERIFY(res2ColId > 0);
0103     QVERIFY(findCol(list, QStringLiteral("res3")).isValid());
0104     res3ColId = findCol(list, QStringLiteral("res3")).id();
0105     QVERIFY(res3ColId > 0);
0106 
0107     col = findCol(list, QStringLiteral("Search"));
0108     searchColId = col.id();
0109     QVERIFY(col.isValid());
0110     QVERIFY(CollectionUtils::isVirtualParent(col));
0111     QCOMPARE(col.resource(), QStringLiteral("akonadi_search_resource"));
0112 }
0113 
0114 void CollectionJobTest::testFolderList()
0115 {
0116     // recursive list of physical folders
0117     auto job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Recursive);
0118     QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived);
0119     QVERIFY(spy.isValid());
0120     AKVERIFYEXEC(job);
0121     Collection::List list = job->collections();
0122 
0123     int count = 0;
0124     for (int i = 0; i < spy.count(); ++i) {
0125         auto l = spy[i][0].value<Akonadi::Collection::List>();
0126         for (int j = 0; j < l.count(); ++j) {
0127             QVERIFY(list.count() > count + j);
0128             QCOMPARE(list[count + j].id(), l[j].id());
0129         }
0130         count += l.count();
0131     }
0132     QCOMPARE(count, list.count());
0133 
0134     // check if everything is there
0135     QCOMPARE(list.count(), 4);
0136     Collection col;
0137     QStringList contentTypes;
0138 
0139     col = findCol(list, QStringLiteral("foo"));
0140     QVERIFY(col.isValid());
0141     QCOMPARE(col.parentCollection().id(), res1ColId);
0142     QVERIFY(CollectionUtils::isFolder(col));
0143     contentTypes << QStringLiteral("message/rfc822") << QStringLiteral("text/calendar") << QStringLiteral("text/directory")
0144                  << QStringLiteral("application/octet-stream") << QStringLiteral("inode/directory");
0145     compareLists(col.contentMimeTypes(), contentTypes);
0146 
0147     QVERIFY(findCol(list, QStringLiteral("bar")).isValid());
0148     QCOMPARE(findCol(list, QStringLiteral("bar")).parentCollection(), col);
0149     QVERIFY(findCol(list, QStringLiteral("bla")).isValid());
0150 }
0151 
0152 class ResultSignalTester : public QObject
0153 {
0154     Q_OBJECT
0155 public:
0156     QStringList receivedSignals;
0157 public Q_SLOTS:
0158     void onCollectionsReceived(const Akonadi::Collection::List & /*unused*/)
0159     {
0160         receivedSignals << QStringLiteral("collectionsReceived");
0161     }
0162 
0163     void onCollectionRetrievalDone(KJob * /*unused*/)
0164     {
0165         receivedSignals << QStringLiteral("result");
0166     }
0167 };
0168 
0169 void CollectionJobTest::testSignalOrder()
0170 {
0171     Akonadi::Collection::List toFetch;
0172     toFetch << Collection(res1ColId);
0173     toFetch << Collection(res2ColId);
0174     auto job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive);
0175     ResultSignalTester spy;
0176     connect(job, &CollectionFetchJob::collectionsReceived, &spy, &ResultSignalTester::onCollectionsReceived);
0177     connect(job, &KJob::result, &spy, &ResultSignalTester::onCollectionRetrievalDone);
0178     AKVERIFYEXEC(job);
0179 
0180     QCOMPARE(spy.receivedSignals.size(), 2);
0181     QCOMPARE(spy.receivedSignals.at(0), QStringLiteral("collectionsReceived"));
0182     QCOMPARE(spy.receivedSignals.at(1), QStringLiteral("result"));
0183 }
0184 
0185 void CollectionJobTest::testNonRecursiveFolderList()
0186 {
0187     auto job = new CollectionFetchJob(Collection(res1ColId), CollectionFetchJob::Base);
0188     AKVERIFYEXEC(job);
0189     Collection::List list = job->collections();
0190 
0191     QCOMPARE(list.count(), 1);
0192     QVERIFY(findCol(list, QStringLiteral("res1")).isValid());
0193 }
0194 
0195 void CollectionJobTest::testEmptyFolderList()
0196 {
0197     auto job = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel);
0198     AKVERIFYEXEC(job);
0199     Collection::List list = job->collections();
0200 
0201     QCOMPARE(list.count(), 0);
0202 }
0203 
0204 void CollectionJobTest::testSearchFolderList()
0205 {
0206     auto job = new CollectionFetchJob(Collection(searchColId), CollectionFetchJob::FirstLevel);
0207     AKVERIFYEXEC(job);
0208     Collection::List list = job->collections();
0209 
0210     QCOMPARE(list.count(), 0);
0211 }
0212 
0213 void CollectionJobTest::testResourceFolderList()
0214 {
0215     // non-existing resource
0216     auto job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
0217     job->fetchScope().setResource(QStringLiteral("i_dont_exist"));
0218     QVERIFY(!job->exec());
0219 
0220     // recursive listing of all collections of an existing resource
0221     job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive);
0222     job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0"));
0223     AKVERIFYEXEC(job);
0224 
0225     Collection::List list = job->collections();
0226     QCOMPARE(list.count(), 5);
0227     QVERIFY(findCol(list, QStringLiteral("res1")).isValid());
0228     QVERIFY(findCol(list, QStringLiteral("foo")).isValid());
0229     QVERIFY(findCol(list, QStringLiteral("bar")).isValid());
0230     QVERIFY(findCol(list, QStringLiteral("bla")).isValid());
0231     int fooId = findCol(list, QStringLiteral("foo")).id();
0232 
0233     // limited listing of a resource
0234     job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive);
0235     job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0"));
0236     AKVERIFYEXEC(job);
0237 
0238     list = job->collections();
0239     QCOMPARE(list.count(), 3);
0240     QVERIFY(findCol(list, QStringLiteral("bar")).isValid());
0241     QVERIFY(findCol(list, QStringLiteral("bla")).isValid());
0242 }
0243 
0244 void CollectionJobTest::testMimeTypeFilter()
0245 {
0246     auto job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive);
0247     job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("message/rfc822"));
0248     AKVERIFYEXEC(job);
0249 
0250     Collection::List list = job->collections();
0251     QCOMPARE(list.count(), 2);
0252     QVERIFY(findCol(list, QStringLiteral("res1")).isValid());
0253     QVERIFY(findCol(list, QStringLiteral("foo")).isValid());
0254     int fooId = findCol(list, QStringLiteral("foo")).id();
0255 
0256     // limited listing of a resource
0257     job = new CollectionFetchJob(Collection(fooId), CollectionFetchJob::Recursive);
0258     job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("message/rfc822"));
0259     AKVERIFYEXEC(job);
0260 
0261     list = job->collections();
0262     QCOMPARE(list.count(), 0);
0263 
0264     // non-existing mimetype
0265     job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this);
0266     job->fetchScope().setContentMimeTypes(QStringList() << QStringLiteral("something/non-existing"));
0267     AKVERIFYEXEC(job);
0268     QCOMPARE(job->collections().size(), 0);
0269 }
0270 
0271 void CollectionJobTest::testCreateDeleteFolder_data()
0272 {
0273     QTest::addColumn<Collection>("collection");
0274     QTest::addColumn<bool>("creatable");
0275 
0276     Collection col;
0277     QTest::newRow("empty") << col << false;
0278     col.setName(QStringLiteral("new folder"));
0279     col.parentCollection().setId(res3ColId);
0280     QTest::newRow("simple") << col << true;
0281 
0282     col.parentCollection().setId(res3ColId);
0283     col.setName(QStringLiteral("foo"));
0284     QTest::newRow("existing in different resource") << col << true;
0285 
0286     col.setName(QStringLiteral("mail folder"));
0287     QStringList mimeTypes;
0288     mimeTypes << QStringLiteral("inode/directory") << QStringLiteral("message/rfc822");
0289     col.setContentMimeTypes(mimeTypes);
0290     col.setRemoteId(QStringLiteral("remote id"));
0291     CachePolicy policy;
0292     policy.setInheritFromParent(false);
0293     policy.setIntervalCheckTime(60);
0294     policy.setLocalParts({QStringLiteral("PLD:ENVELOPE")});
0295     policy.setSyncOnDemand(true);
0296     policy.setCacheTimeout(120);
0297     col.setCachePolicy(policy);
0298     QTest::newRow("complex") << col << true;
0299 
0300     col = Collection();
0301     col.setName(QStringLiteral("New Folder"));
0302     col.parentCollection().setId(searchColId);
0303     QTest::newRow("search folder") << col << false;
0304 
0305     col.parentCollection().setId(res2ColId);
0306     col.setName(QStringLiteral("foo2"));
0307     QTest::newRow("already existing") << col << false;
0308 
0309     col.parentCollection().setId(res2ColId); // Sibling of collection 'foo2'
0310     col.setName(QStringLiteral("foo2 "));
0311     QTest::newRow("name of an sibling with an additional ending space") << col << true;
0312 
0313     col.setName(QStringLiteral("Bla"));
0314     col.parentCollection().setId(2);
0315     QTest::newRow("already existing with different case") << col << true;
0316 
0317     auto resolver = new CollectionPathResolver(QStringLiteral("res2/foo2"), this);
0318     AKVERIFYEXEC(resolver);
0319     col.parentCollection().setId(resolver->collection());
0320     col.setName(QStringLiteral("new folder"));
0321     QTest::newRow("parent noinferior") << col << false;
0322 
0323     col.parentCollection().setId(INT_MAX);
0324     QTest::newRow("missing parent") << col << false;
0325 
0326     col = Collection();
0327     col.setName(QStringLiteral("rid parent"));
0328     col.parentCollection().setRemoteId(QStringLiteral("8"));
0329     QTest::newRow("rid parent") << col << false; // missing resource context
0330 }
0331 
0332 void CollectionJobTest::testCreateDeleteFolder()
0333 {
0334     QFETCH(Collection, collection);
0335     QFETCH(bool, creatable);
0336 
0337     auto createJob = new CollectionCreateJob(collection, this);
0338     QCOMPARE(createJob->exec(), creatable);
0339     if (!creatable) {
0340         return;
0341     }
0342 
0343     Collection createdCol = createJob->collection();
0344     QVERIFY(createdCol.isValid());
0345     QCOMPARE(createdCol.name(), collection.name());
0346     QCOMPARE(createdCol.parentCollection(), collection.parentCollection());
0347     QCOMPARE(createdCol.remoteId(), collection.remoteId());
0348     QCOMPARE(createdCol.cachePolicy(), collection.cachePolicy());
0349 
0350     auto listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this);
0351     AKVERIFYEXEC(listJob);
0352     Collection listedCol = findCol(listJob->collections(), collection.name());
0353     QCOMPARE(listedCol, createdCol);
0354     QCOMPARE(listedCol.remoteId(), collection.remoteId());
0355     QCOMPARE(listedCol.cachePolicy(), collection.cachePolicy());
0356 
0357     // fetch parent to compare inherited collection properties
0358     Collection parentCol = Collection::root();
0359     if (collection.parentCollection().isValid()) {
0360         auto newListJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::Base, this);
0361         AKVERIFYEXEC(newListJob);
0362         QCOMPARE(newListJob->collections().count(), 1);
0363         parentCol = newListJob->collections().first();
0364     }
0365 
0366     if (collection.contentMimeTypes().isEmpty()) {
0367         compareLists(listedCol.contentMimeTypes(), parentCol.contentMimeTypes());
0368     } else {
0369         compareLists(listedCol.contentMimeTypes(), collection.contentMimeTypes());
0370     }
0371 
0372     if (collection.resource().isEmpty()) {
0373         QCOMPARE(listedCol.resource(), parentCol.resource());
0374     } else {
0375         QCOMPARE(listedCol.resource(), collection.resource());
0376     }
0377 
0378     auto delJob = new CollectionDeleteJob(createdCol, this);
0379     AKVERIFYEXEC(delJob);
0380 
0381     listJob = new CollectionFetchJob(collection.parentCollection(), CollectionFetchJob::FirstLevel, this);
0382     AKVERIFYEXEC(listJob);
0383     QVERIFY(!findCol(listJob->collections(), collection.name()).isValid());
0384 }
0385 
0386 void CollectionJobTest::testIllegalDeleteFolder()
0387 {
0388     // non-existing folder
0389     auto del = new CollectionDeleteJob(Collection(INT_MAX), this);
0390     QVERIFY(!del->exec());
0391 
0392     // root
0393     del = new CollectionDeleteJob(Collection::root(), this);
0394     QVERIFY(!del->exec());
0395 }
0396 
0397 void CollectionJobTest::testStatistics()
0398 {
0399     // empty folder
0400     auto statistics = new CollectionStatisticsJob(Collection(res1ColId), this);
0401     AKVERIFYEXEC(statistics);
0402 
0403     CollectionStatistics s = statistics->statistics();
0404     QCOMPARE(s.count(), 0LL);
0405     QCOMPARE(s.unreadCount(), 0LL);
0406 
0407     // folder with attributes and content
0408     auto resolver = new CollectionPathResolver(QStringLiteral("res1/foo"), this);
0409     AKVERIFYEXEC(resolver);
0410     statistics = new CollectionStatisticsJob(Collection(resolver->collection()), this);
0411     AKVERIFYEXEC(statistics);
0412 
0413     s = statistics->statistics();
0414     QCOMPARE(s.count(), 15LL);
0415     QCOMPARE(s.unreadCount(), 14LL);
0416 }
0417 
0418 void CollectionJobTest::testModify_data()
0419 {
0420     QTest::addColumn<qint64>("uid");
0421     QTest::addColumn<QString>("rid");
0422 
0423     QTest::newRow("uid") << AkonadiTest::collectionIdFromPath(QStringLiteral("res1/foo")) << QString();
0424     QTest::newRow("rid") << -1LL << QStringLiteral("10");
0425 }
0426 
0427 #define RESET_COLLECTION_ID                                                                                                                                    \
0428     col.setId(uid);                                                                                                                                            \
0429     if (!rid.isEmpty())                                                                                                                                        \
0430     col.setRemoteId(rid)
0431 
0432 void CollectionJobTest::testModify()
0433 {
0434     QFETCH(qint64, uid);
0435     QFETCH(QString, rid);
0436 
0437     if (!rid.isEmpty()) {
0438         auto rjob = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"));
0439         AKVERIFYEXEC(rjob);
0440     }
0441 
0442     const QStringList reference = {QStringLiteral("text/calendar"),
0443                                    QStringLiteral("text/directory"),
0444                                    QStringLiteral("message/rfc822"),
0445                                    QStringLiteral("application/octet-stream"),
0446                                    QStringLiteral("inode/directory")};
0447 
0448     Collection col;
0449     RESET_COLLECTION_ID;
0450 
0451     // test noop modify
0452     auto mod = new CollectionModifyJob(col, this);
0453     AKVERIFYEXEC(mod);
0454 
0455     auto ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0456     AKVERIFYEXEC(ljob);
0457     QCOMPARE(ljob->collections().count(), 1);
0458     col = ljob->collections().first();
0459     compareLists(col.contentMimeTypes(), reference);
0460 
0461     // test clearing content types
0462     RESET_COLLECTION_ID;
0463     col.setContentMimeTypes(QStringList());
0464     mod = new CollectionModifyJob(col, this);
0465     AKVERIFYEXEC(mod);
0466 
0467     ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0468     AKVERIFYEXEC(ljob);
0469     QCOMPARE(ljob->collections().count(), 1);
0470     col = ljob->collections().first();
0471     QVERIFY(col.contentMimeTypes().isEmpty());
0472 
0473     // test setting contnet types
0474     RESET_COLLECTION_ID;
0475     col.setContentMimeTypes(reference);
0476     mod = new CollectionModifyJob(col, this);
0477     AKVERIFYEXEC(mod);
0478 
0479     ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0480     AKVERIFYEXEC(ljob);
0481     QCOMPARE(ljob->collections().count(), 1);
0482     col = ljob->collections().first();
0483     compareLists(col.contentMimeTypes(), reference);
0484 
0485     // add attribute
0486     RESET_COLLECTION_ID;
0487     col.attribute<TestAttribute>(Collection::AddIfMissing)->data = "new";
0488     mod = new CollectionModifyJob(col, this);
0489     AKVERIFYEXEC(mod);
0490 
0491     ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0492     AKVERIFYEXEC(ljob);
0493     QVERIFY(ljob->collections().first().hasAttribute<TestAttribute>());
0494     QCOMPARE(ljob->collections().first().attribute<TestAttribute>()->data, QByteArray("new"));
0495 
0496     // modify existing attribute
0497     RESET_COLLECTION_ID;
0498     col.attribute<TestAttribute>()->data = "modified";
0499     mod = new CollectionModifyJob(col, this);
0500     AKVERIFYEXEC(mod);
0501 
0502     ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0503     AKVERIFYEXEC(ljob);
0504     QVERIFY(ljob->collections().first().hasAttribute<TestAttribute>());
0505     QCOMPARE(ljob->collections().first().attribute<TestAttribute>()->data, QByteArray("modified"));
0506 
0507     // renaming
0508     RESET_COLLECTION_ID;
0509     col.setName(QStringLiteral("foo (renamed)"));
0510     mod = new CollectionModifyJob(col, this);
0511     AKVERIFYEXEC(mod);
0512 
0513     ljob = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0514     AKVERIFYEXEC(ljob);
0515     QCOMPARE(ljob->collections().count(), 1);
0516     col = ljob->collections().first();
0517     QCOMPARE(col.name(), QStringLiteral("foo (renamed)"));
0518 
0519     RESET_COLLECTION_ID;
0520     col.setName(QStringLiteral("foo"));
0521     mod = new CollectionModifyJob(col, this);
0522     AKVERIFYEXEC(mod);
0523 }
0524 
0525 #undef RESET_COLLECTION_ID
0526 
0527 void CollectionJobTest::testIllegalModify()
0528 {
0529     // non-existing collection
0530     Collection col(INT_MAX);
0531     col.parentCollection().setId(res1ColId);
0532     auto mod = new CollectionModifyJob(col, this);
0533     QVERIFY(!mod->exec());
0534 
0535     // rename to already existing name
0536     col = Collection(res1ColId);
0537     col.setName(QStringLiteral("res2"));
0538     mod = new CollectionModifyJob(col, this);
0539     QVERIFY(!mod->exec());
0540 }
0541 
0542 void CollectionJobTest::testUtf8CollectionName_data()
0543 {
0544     QTest::addColumn<QString>("folderName");
0545 
0546     QTest::newRow("Umlaut") << QString::fromUtf8("ä");
0547     QTest::newRow("Garbage") << QString::fromUtf8("đ→³}đþøæſð");
0548     QTest::newRow("Utf8") << QString::fromUtf8("日本語");
0549 }
0550 
0551 void CollectionJobTest::testUtf8CollectionName()
0552 {
0553     QFETCH(QString, folderName);
0554 
0555     // create collection
0556     Collection col;
0557     col.parentCollection().setId(res3ColId);
0558     col.setName(folderName);
0559     auto create = new CollectionCreateJob(col, this);
0560     AKVERIFYEXEC(create);
0561     col = create->collection();
0562     QVERIFY(col.isValid());
0563     QCOMPARE(col.name(), folderName);
0564 
0565     // list parent
0566     auto list = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::Recursive, this);
0567     AKVERIFYEXEC(list);
0568     QCOMPARE(list->collections().count(), 1);
0569     QCOMPARE(list->collections().first(), col);
0570     QCOMPARE(list->collections().first().name(), col.name());
0571 
0572     // modify collection
0573     col.setContentMimeTypes({QStringLiteral("message/rfc822")});
0574     auto modify = new CollectionModifyJob(col, this);
0575     AKVERIFYEXEC(modify);
0576 
0577     // collection statistics
0578     auto statistics = new CollectionStatisticsJob(col, this);
0579     AKVERIFYEXEC(statistics);
0580     CollectionStatistics s = statistics->statistics();
0581     QCOMPARE(s.count(), 0LL);
0582     QCOMPARE(s.unreadCount(), 0LL);
0583 
0584     // delete collection
0585     auto del = new CollectionDeleteJob(col, this);
0586     AKVERIFYEXEC(del);
0587 }
0588 
0589 void CollectionJobTest::testMultiList()
0590 {
0591     Collection::List req;
0592     req << Collection(res1ColId) << Collection(res2ColId);
0593     auto job = new CollectionFetchJob(req, this);
0594     AKVERIFYEXEC(job);
0595 
0596     Collection::List res;
0597     res = job->collections();
0598     compareLists(res, req);
0599 }
0600 
0601 void CollectionJobTest::testMultiListInvalid()
0602 {
0603     Collection::List req;
0604     req << Collection(res1ColId) << Collection(1234567) << Collection(res2ColId);
0605     auto job = new CollectionFetchJob(req, this);
0606     QVERIFY(!job->exec());
0607     // not all available collections are fetched
0608     QVERIFY(job->collections().count() != 2);
0609 
0610     job = new CollectionFetchJob(req, this);
0611     job->fetchScope().setIgnoreRetrievalErrors(true);
0612     QVERIFY(!job->exec());
0613     Collection::List res;
0614     res = job->collections();
0615     req = Collection::List() << Collection(res1ColId) << Collection(res2ColId);
0616     compareLists(res, req);
0617 }
0618 
0619 void CollectionJobTest::testRecursiveMultiList()
0620 {
0621     Akonadi::Collection::List toFetch;
0622     toFetch << Collection(res1ColId);
0623     toFetch << Collection(res2ColId);
0624     auto job = new CollectionFetchJob(toFetch, CollectionFetchJob::Recursive);
0625     QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived);
0626     QVERIFY(spy.isValid());
0627     AKVERIFYEXEC(job);
0628 
0629     Collection::List list = job->collections();
0630 
0631     int count = 0;
0632     for (int i = 0; i < spy.count(); ++i) {
0633         auto l = spy[i][0].value<Akonadi::Collection::List>();
0634         for (int j = 0; j < l.count(); ++j) {
0635             QVERIFY(list.count() > count + j);
0636             QCOMPARE(list[count + j].id(), l[j].id());
0637         }
0638         count += l.count();
0639     }
0640     QCOMPARE(count, list.count());
0641 
0642     // check if everything is there
0643     QCOMPARE(list.count(), 4 + 2);
0644     QVERIFY(findCol(list, QStringLiteral("foo")).isValid());
0645     QVERIFY(findCol(list, QStringLiteral("bar")).isValid());
0646     QVERIFY(findCol(list, QStringLiteral("bla")).isValid()); // There are two bla folders, but we only check for one.
0647     QVERIFY(findCol(list, QStringLiteral("foo2")).isValid());
0648     QVERIFY(findCol(list, QStringLiteral("space folder")).isValid());
0649 }
0650 
0651 void CollectionJobTest::testNonOverlappingRootList()
0652 {
0653     Akonadi::Collection::List toFetch;
0654     toFetch << Collection(res1ColId);
0655     toFetch << Collection(res2ColId);
0656     auto job = new CollectionFetchJob(toFetch, CollectionFetchJob::NonOverlappingRoots);
0657     QSignalSpy spy(job, &CollectionFetchJob::collectionsReceived);
0658     QVERIFY(spy.isValid());
0659     AKVERIFYEXEC(job);
0660 
0661     Collection::List list = job->collections();
0662 
0663     int count = 0;
0664     for (int i = 0; i < spy.count(); ++i) {
0665         auto l = spy[i][0].value<Akonadi::Collection::List>();
0666         for (int j = 0; j < l.count(); ++j) {
0667             QVERIFY(list.count() > count + j);
0668             QCOMPARE(list[count + j].id(), l[j].id());
0669         }
0670         count += l.count();
0671     }
0672     QCOMPARE(count, list.count());
0673 
0674     // check if everything is there
0675     QCOMPARE(list.count(), 2);
0676     QVERIFY(findCol(list, QStringLiteral("res1")).isValid());
0677     QVERIFY(findCol(list, QStringLiteral("res2")).isValid());
0678 }
0679 
0680 void CollectionJobTest::testRidFetch()
0681 {
0682     Collection col;
0683     col.setRemoteId(QStringLiteral("10"));
0684 
0685     auto job = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0686     job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0"));
0687     AKVERIFYEXEC(job);
0688     QCOMPARE(job->collections().count(), 1);
0689     col = job->collections().first();
0690     QVERIFY(col.isValid());
0691     QCOMPARE(col.remoteId(), QString::fromLatin1("10"));
0692 }
0693 
0694 void CollectionJobTest::testRidCreateDelete_data()
0695 {
0696     QTest::addColumn<QString>("remoteId");
0697     QTest::newRow("ASCII") << QString::fromUtf8("MY REMOTE ID");
0698     QTest::newRow("LATIN1") << QString::fromUtf8("MY REMÖTE ID");
0699     QTest::newRow("UTF8") << QString::fromUtf8("MY REMOTE 検索表");
0700 }
0701 
0702 void CollectionJobTest::testRidCreateDelete()
0703 {
0704     QFETCH(QString, remoteId);
0705     Collection collection;
0706     collection.setName(QStringLiteral("rid create"));
0707     collection.parentCollection().setRemoteId(QStringLiteral("8"));
0708     collection.setRemoteId(remoteId);
0709 
0710     auto resSel = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_2"));
0711     AKVERIFYEXEC(resSel);
0712 
0713     auto createJob = new CollectionCreateJob(collection, this);
0714     AKVERIFYEXEC(createJob);
0715 
0716     Collection createdCol = createJob->collection();
0717     QVERIFY(createdCol.isValid());
0718     QCOMPARE(createdCol.name(), collection.name());
0719 
0720     auto listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this);
0721     AKVERIFYEXEC(listJob);
0722     Collection listedCol = findCol(listJob->collections(), collection.name());
0723     QCOMPARE(listedCol, createdCol);
0724     QCOMPARE(listedCol.name(), collection.name());
0725 
0726     QVERIFY(!collection.isValid());
0727     auto delJob = new CollectionDeleteJob(collection, this);
0728     AKVERIFYEXEC(delJob);
0729 
0730     listJob = new CollectionFetchJob(Collection(res3ColId), CollectionFetchJob::FirstLevel, this);
0731     AKVERIFYEXEC(listJob);
0732     QVERIFY(!findCol(listJob->collections(), collection.name()).isValid());
0733 }
0734 
0735 void CollectionJobTest::testAncestorRetrieval()
0736 {
0737     Collection col;
0738     col.setRemoteId(QStringLiteral("10"));
0739 
0740     auto job = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0741     job->fetchScope().setResource(QStringLiteral("akonadi_knut_resource_0"));
0742     job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All);
0743     AKVERIFYEXEC(job);
0744     QCOMPARE(job->collections().count(), 1);
0745     col = job->collections().first();
0746     QVERIFY(col.isValid());
0747     QVERIFY(col.parentCollection().isValid());
0748     QCOMPARE(col.parentCollection().remoteId(), QStringLiteral("6"));
0749     QCOMPARE(col.parentCollection().parentCollection(), Collection::root());
0750 
0751     auto select = new ResourceSelectJob(QStringLiteral("akonadi_knut_resource_0"), this);
0752     AKVERIFYEXEC(select);
0753     Collection col2(col);
0754     col2.setId(-1); // make it invalid but keep the ancestor chain
0755     job = new CollectionFetchJob(col2, CollectionFetchJob::Base, this);
0756     AKVERIFYEXEC(job);
0757     QCOMPARE(job->collections().count(), 1);
0758     col2 = job->collections().first();
0759     QVERIFY(col2.isValid());
0760     QCOMPARE(col, col2);
0761 }
0762 
0763 void CollectionJobTest::testAncestorAttributeRetrieval()
0764 {
0765     Akonadi::Collection baseCol;
0766     {
0767         baseCol.setParentCollection(Akonadi::Collection(res1ColId));
0768         baseCol.setName(QStringLiteral("base"));
0769         baseCol.attribute<TestAttribute>(Collection::AddIfMissing)->data = "new";
0770         auto create = new Akonadi::CollectionCreateJob(baseCol);
0771         AKVERIFYEXEC(create);
0772         baseCol = create->collection();
0773     }
0774     {
0775         Akonadi::Collection col;
0776         col.setParentCollection(baseCol);
0777         col.setName(QStringLiteral("enabled"));
0778         auto create = new Akonadi::CollectionCreateJob(col);
0779         AKVERIFYEXEC(create);
0780 
0781         auto job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base);
0782         job->fetchScope().setAncestorRetrieval(CollectionFetchScope::All);
0783         job->fetchScope().ancestorFetchScope().setFetchIdOnly(false);
0784         job->fetchScope().ancestorFetchScope().fetchAttribute<TestAttribute>();
0785         AKVERIFYEXEC(job);
0786         Akonadi::Collection result = job->collections().first();
0787         QCOMPARE(result.parentCollection().hasAttribute<TestAttribute>(), true);
0788     }
0789 
0790     // Cleanup
0791     auto deleteJob = new CollectionDeleteJob(baseCol);
0792     AKVERIFYEXEC(deleteJob);
0793 }
0794 
0795 void CollectionJobTest::testListPreference()
0796 {
0797     Akonadi::Collection baseCol;
0798     {
0799         baseCol.setParentCollection(Akonadi::Collection(res1ColId));
0800         baseCol.setName(QStringLiteral("base"));
0801         auto create = new Akonadi::CollectionCreateJob(baseCol);
0802         AKVERIFYEXEC(create);
0803         baseCol = create->collection();
0804     }
0805     {
0806         Akonadi::Collection col;
0807         col.setParentCollection(baseCol);
0808         col.setEnabled(true);
0809         col.setName(QStringLiteral("enabled"));
0810         auto create = new Akonadi::CollectionCreateJob(col);
0811         AKVERIFYEXEC(create);
0812 
0813         auto job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base);
0814         AKVERIFYEXEC(job);
0815         Akonadi::Collection result = job->collections().first();
0816         QCOMPARE(result.enabled(), true);
0817         QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDefault);
0818         QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDefault);
0819         QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDefault);
0820     }
0821     {
0822         Akonadi::Collection col;
0823         col.setParentCollection(baseCol);
0824         col.setName(QStringLiteral("disabledPref"));
0825         col.setEnabled(true);
0826         col.setLocalListPreference(Collection::ListDisplay, Collection::ListDisabled);
0827         col.setLocalListPreference(Collection::ListSync, Collection::ListDisabled);
0828         col.setLocalListPreference(Collection::ListIndex, Collection::ListDisabled);
0829         auto create = new Akonadi::CollectionCreateJob(col);
0830         AKVERIFYEXEC(create);
0831         auto job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base);
0832         AKVERIFYEXEC(job);
0833         Akonadi::Collection result = job->collections().first();
0834         QCOMPARE(result.enabled(), true);
0835         QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListDisabled);
0836         QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListDisabled);
0837         QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListDisabled);
0838     }
0839     {
0840         Akonadi::Collection col;
0841         col.setParentCollection(baseCol);
0842         col.setName(QStringLiteral("enabledPref"));
0843         col.setEnabled(false);
0844         col.setLocalListPreference(Collection::ListDisplay, Collection::ListEnabled);
0845         col.setLocalListPreference(Collection::ListSync, Collection::ListEnabled);
0846         col.setLocalListPreference(Collection::ListIndex, Collection::ListEnabled);
0847         auto create = new Akonadi::CollectionCreateJob(col);
0848         AKVERIFYEXEC(create);
0849         auto job = new CollectionFetchJob(create->collection(), CollectionFetchJob::Base);
0850         AKVERIFYEXEC(job);
0851         Akonadi::Collection result = job->collections().first();
0852         QCOMPARE(result.enabled(), false);
0853         QCOMPARE(result.localListPreference(Collection::ListDisplay), Collection::ListEnabled);
0854         QCOMPARE(result.localListPreference(Collection::ListSync), Collection::ListEnabled);
0855         QCOMPARE(result.localListPreference(Collection::ListIndex), Collection::ListEnabled);
0856     }
0857 
0858     // Check list filter
0859     {
0860         auto job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel);
0861         job->fetchScope().setListFilter(CollectionFetchScope::Display);
0862         AKVERIFYEXEC(job);
0863         QCOMPARE(job->collections().size(), 2);
0864     }
0865     {
0866         auto job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel);
0867         job->fetchScope().setListFilter(CollectionFetchScope::Sync);
0868         AKVERIFYEXEC(job);
0869         QCOMPARE(job->collections().size(), 2);
0870     }
0871     {
0872         auto job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel);
0873         job->fetchScope().setListFilter(CollectionFetchScope::Index);
0874         AKVERIFYEXEC(job);
0875         QCOMPARE(job->collections().size(), 2);
0876     }
0877     {
0878         auto job = new CollectionFetchJob(baseCol, CollectionFetchJob::FirstLevel);
0879         job->fetchScope().setListFilter(CollectionFetchScope::Enabled);
0880         AKVERIFYEXEC(job);
0881         QCOMPARE(job->collections().size(), 2);
0882     }
0883 
0884     // Cleanup
0885     auto deleteJob = new CollectionDeleteJob(baseCol);
0886     AKVERIFYEXEC(deleteJob);
0887 }
0888 
0889 #include "collectionjobtest.moc"
0890 
0891 #include "moc_collectionjobtest.cpp"