File indexing completed on 2024-11-24 04:44:33

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0003     SPDX-FileContributor: Kevin Krammer <krake@kdab.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "abstractlocalstore.h"
0009 
0010 #include "collectioncreatejob.h"
0011 #include "collectiondeletejob.h"
0012 #include "collectionfetchjob.h"
0013 #include "collectionmodifyjob.h"
0014 #include "collectionmovejob.h"
0015 #include "itemcreatejob.h"
0016 #include "itemdeletejob.h"
0017 #include "itemfetchjob.h"
0018 #include "itemmodifyjob.h"
0019 #include "itemmovejob.h"
0020 #include "sessionimpls_p.h"
0021 #include "storecompactjob.h"
0022 
0023 #include <KRandom>
0024 #include <QRandomGenerator>
0025 
0026 #include <QTest>
0027 
0028 using namespace Akonadi;
0029 using namespace Akonadi::FileStore;
0030 
0031 class TestStore : public AbstractLocalStore
0032 {
0033     Q_OBJECT
0034 
0035 public:
0036     TestStore()
0037         : mLastCheckedJob(nullptr)
0038         , mLastProcessedJob(nullptr)
0039         , mErrorCode(0)
0040     {
0041     }
0042 
0043 public:
0044     mutable Akonadi::FileStore::Job *mLastCheckedJob = nullptr;
0045     Akonadi::FileStore::Job *mLastProcessedJob = nullptr;
0046 
0047     Collection mTopLevelCollection;
0048 
0049     int mErrorCode;
0050     QString mErrorText;
0051 
0052 protected:
0053     void processJob(Akonadi::FileStore::Job *job) override;
0054 
0055 protected:
0056     void setTopLevelCollection(const Collection &collection) override
0057     {
0058         mTopLevelCollection = collection;
0059 
0060         Collection modifiedCollection = collection;
0061         modifiedCollection.setContentMimeTypes(QStringList() << Collection::mimeType());
0062 
0063         AbstractLocalStore::setTopLevelCollection(modifiedCollection);
0064     }
0065 
0066     void checkCollectionCreate(Akonadi::FileStore::CollectionCreateJob *job, int &errorCode, QString &errorText) const override
0067     {
0068         mLastCheckedJob = job;
0069         errorCode = mErrorCode;
0070         errorText = mErrorText;
0071     }
0072 
0073     void checkCollectionDelete(Akonadi::FileStore::CollectionDeleteJob *job, int &errorCode, QString &errorText) const override
0074     {
0075         mLastCheckedJob = job;
0076         errorCode = mErrorCode;
0077         errorText = mErrorText;
0078     }
0079 
0080     void checkCollectionFetch(Akonadi::FileStore::CollectionFetchJob *job, int &errorCode, QString &errorText) const override
0081     {
0082         mLastCheckedJob = job;
0083         errorCode = mErrorCode;
0084         errorText = mErrorText;
0085     }
0086 
0087     void checkCollectionModify(Akonadi::FileStore::CollectionModifyJob *job, int &errorCode, QString &errorText) const override
0088     {
0089         mLastCheckedJob = job;
0090         errorCode = mErrorCode;
0091         errorText = mErrorText;
0092     }
0093 
0094     void checkCollectionMove(Akonadi::FileStore::CollectionMoveJob *job, int &errorCode, QString &errorText) const override
0095     {
0096         mLastCheckedJob = job;
0097         errorCode = mErrorCode;
0098         errorText = mErrorText;
0099     }
0100 
0101     void checkItemCreate(Akonadi::FileStore::ItemCreateJob *job, int &errorCode, QString &errorText) const override
0102     {
0103         mLastCheckedJob = job;
0104         errorCode = mErrorCode;
0105         errorText = mErrorText;
0106     }
0107 
0108     void checkItemDelete(Akonadi::FileStore::ItemDeleteJob *job, int &errorCode, QString &errorText) const override
0109     {
0110         mLastCheckedJob = job;
0111         errorCode = mErrorCode;
0112         errorText = mErrorText;
0113     }
0114 
0115     void checkItemFetch(Akonadi::FileStore::ItemFetchJob *job, int &errorCode, QString &errorText) const override
0116     {
0117         mLastCheckedJob = job;
0118         errorCode = mErrorCode;
0119         errorText = mErrorText;
0120     }
0121 
0122     void checkItemModify(Akonadi::FileStore::ItemModifyJob *job, int &errorCode, QString &errorText) const override
0123     {
0124         mLastCheckedJob = job;
0125         errorCode = mErrorCode;
0126         errorText = mErrorText;
0127     }
0128 
0129     void checkItemMove(Akonadi::FileStore::ItemMoveJob *job, int &errorCode, QString &errorText) const override
0130     {
0131         mLastCheckedJob = job;
0132         errorCode = mErrorCode;
0133         errorText = mErrorText;
0134     }
0135 
0136     void checkStoreCompact(Akonadi::FileStore::StoreCompactJob *job, int &errorCode, QString &errorText) const override
0137     {
0138         mLastCheckedJob = job;
0139         errorCode = mErrorCode;
0140         errorText = mErrorText;
0141     }
0142 };
0143 
0144 void TestStore::processJob(Akonadi::FileStore::Job *job)
0145 {
0146     mLastProcessedJob = job;
0147 
0148     QCOMPARE(currentJob(), job);
0149     QVERIFY(job->error() == 0);
0150 
0151     if (mErrorCode != 0) {
0152         notifyError(mErrorCode, mErrorText);
0153     }
0154 }
0155 
0156 class AbstractLocalStoreTest : public QObject
0157 {
0158     Q_OBJECT
0159 
0160 public:
0161     AbstractLocalStoreTest()
0162         : QObject()
0163         , mStore(nullptr)
0164     {
0165     }
0166 
0167     ~AbstractLocalStoreTest() override
0168     {
0169         delete mStore;
0170     }
0171 
0172 private:
0173     TestStore *mStore = nullptr;
0174 
0175 private Q_SLOTS:
0176     void init();
0177     void testSetPath();
0178     void testCreateCollection();
0179     void testDeleteCollection();
0180     void testFetchCollection();
0181     void testModifyCollection();
0182     void testMoveCollection();
0183     void testFetchItems();
0184     void testFetchItem();
0185     void testCreateItem();
0186     void testDeleteItem();
0187     void testModifyItem();
0188     void testMoveItem();
0189     void testCompactStore();
0190 };
0191 
0192 void AbstractLocalStoreTest::init()
0193 {
0194     delete mStore;
0195     mStore = new TestStore;
0196 }
0197 
0198 void AbstractLocalStoreTest::testSetPath()
0199 {
0200     const QString file = KRandom::randomString(10);
0201     const QString path = QLatin1StringView("/tmp/test/") + file;
0202 
0203     // check that setTopLevelCollection() has been called
0204     mStore->setPath(path);
0205     QCOMPARE(mStore->mTopLevelCollection.remoteId(), path);
0206 
0207     // check that the modified collection is the one returned by topLevelCollection()
0208     QVERIFY(mStore->mTopLevelCollection.contentMimeTypes().isEmpty());
0209     QCOMPARE(mStore->topLevelCollection().remoteId(), path);
0210     QCOMPARE(mStore->topLevelCollection().contentMimeTypes(), QStringList() << Collection::mimeType());
0211     QCOMPARE(mStore->topLevelCollection().name(), file);
0212 
0213     // check that calling with the same path again, does not call the template method
0214     mStore->mTopLevelCollection = Collection();
0215     mStore->setPath(path);
0216     QVERIFY(mStore->mTopLevelCollection.remoteId().isEmpty());
0217     QCOMPARE(mStore->topLevelCollection().remoteId(), path);
0218     QCOMPARE(mStore->topLevelCollection().contentMimeTypes(), QStringList() << Collection::mimeType());
0219     QCOMPARE(mStore->topLevelCollection().name(), file);
0220 
0221     // check that calling with a different path works like the first call
0222     const QString file2 = KRandom::randomString(10);
0223     const QString path2 = QLatin1StringView("/tmp/test2/") + file2;
0224 
0225     mStore->setPath(path2);
0226     QCOMPARE(mStore->mTopLevelCollection.remoteId(), path2);
0227     QCOMPARE(mStore->topLevelCollection().remoteId(), path2);
0228     QCOMPARE(mStore->topLevelCollection().contentMimeTypes(), QStringList() << Collection::mimeType());
0229     QCOMPARE(mStore->topLevelCollection().name(), file2);
0230 }
0231 
0232 void AbstractLocalStoreTest::testCreateCollection()
0233 {
0234     Akonadi::FileStore::CollectionCreateJob *job = nullptr;
0235 
0236     // test without setPath()
0237     job = mStore->createCollection(Collection(), Collection());
0238     QVERIFY(job != nullptr);
0239     QCOMPARE(mStore->mLastCheckedJob, job);
0240     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0241     QVERIFY(!job->errorText().isEmpty());
0242 
0243     QVERIFY(!job->exec());
0244     QVERIFY(mStore->mLastProcessedJob == nullptr);
0245 
0246     // test with path but with invalid collections
0247     mStore->setPath(QStringLiteral("/tmp/test"));
0248     job = mStore->createCollection(Collection(), Collection());
0249     QVERIFY(job != nullptr);
0250     QCOMPARE(mStore->mLastCheckedJob, job);
0251     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0252     QVERIFY(!job->errorText().isEmpty());
0253 
0254     QVERIFY(!job->exec());
0255     QVERIFY(mStore->mLastProcessedJob == nullptr);
0256 
0257     // test with potentially valid collection (has remoteId), but invalid target parent
0258     Collection collection;
0259     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0260     job = mStore->createCollection(collection, Collection());
0261     QVERIFY(job != nullptr);
0262     QCOMPARE(mStore->mLastCheckedJob, job);
0263     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0264     QVERIFY(!job->errorText().isEmpty());
0265 
0266     QVERIFY(!job->exec());
0267     QVERIFY(mStore->mLastProcessedJob == nullptr);
0268 
0269     // test with potentially valid collections
0270     Collection targetParent;
0271     targetParent.setRemoteId(QStringLiteral("/tmp/test2"));
0272     job = mStore->createCollection(collection, targetParent);
0273     QVERIFY(job != nullptr);
0274     QCOMPARE(mStore->mLastCheckedJob, job);
0275     QCOMPARE(job->error(), 0);
0276     QVERIFY(job->errorText().isEmpty());
0277 
0278     QVERIFY(job->exec());
0279     QCOMPARE(mStore->mLastProcessedJob, job);
0280     mStore->mLastProcessedJob = nullptr;
0281 
0282     // test template check method
0283     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0284     mStore->mErrorText = KRandom::randomString(10);
0285 
0286     job = mStore->createCollection(collection, targetParent);
0287     QVERIFY(job != nullptr);
0288     QCOMPARE(mStore->mLastCheckedJob, job);
0289     QCOMPARE(job->error(), mStore->mErrorCode);
0290     QCOMPARE(job->errorText(), mStore->mErrorText);
0291 
0292     QVERIFY(!job->exec());
0293     QVERIFY(mStore->mLastProcessedJob == nullptr);
0294     mStore->mErrorCode = 0;
0295     mStore->mErrorText = QString();
0296 }
0297 
0298 void AbstractLocalStoreTest::testDeleteCollection()
0299 {
0300     Akonadi::FileStore::CollectionDeleteJob *job = nullptr;
0301 
0302     // test without setPath()
0303     job = mStore->deleteCollection(Collection());
0304     QVERIFY(job != nullptr);
0305     QCOMPARE(mStore->mLastCheckedJob, job);
0306     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0307     QVERIFY(!job->errorText().isEmpty());
0308 
0309     QVERIFY(!job->exec());
0310     QVERIFY(mStore->mLastProcessedJob == nullptr);
0311 
0312     // test with path but with invalid collection
0313     mStore->setPath(QStringLiteral("/tmp/test"));
0314     job = mStore->deleteCollection(Collection());
0315     QVERIFY(job != nullptr);
0316     QCOMPARE(mStore->mLastCheckedJob, job);
0317     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0318     QVERIFY(!job->errorText().isEmpty());
0319 
0320     QVERIFY(!job->exec());
0321     QVERIFY(mStore->mLastProcessedJob == nullptr);
0322 
0323     // test with ivalid collection (has remoteId, but no parent collection remoteId)
0324     Collection collection;
0325     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0326     job = mStore->deleteCollection(collection);
0327     QVERIFY(job != nullptr);
0328     QCOMPARE(mStore->mLastCheckedJob, job);
0329     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0330     QVERIFY(!job->errorText().isEmpty());
0331 
0332     QVERIFY(!job->exec());
0333     QVERIFY(mStore->mLastProcessedJob == nullptr);
0334 
0335     // test with potentially valid collection (has remoteId and parent collection remoteId)
0336     Collection parentCollection;
0337     parentCollection.setRemoteId(QStringLiteral("/tmp/test"));
0338     collection.setParentCollection(parentCollection);
0339     job = mStore->deleteCollection(collection);
0340     QVERIFY(job != nullptr);
0341     QCOMPARE(mStore->mLastCheckedJob, job);
0342     QCOMPARE(job->error(), 0);
0343     QVERIFY(job->errorText().isEmpty());
0344 
0345     QVERIFY(job->exec());
0346     QCOMPARE(mStore->mLastProcessedJob, job);
0347     mStore->mLastProcessedJob = nullptr;
0348 
0349     // test template check method
0350     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0351     mStore->mErrorText = KRandom::randomString(10);
0352 
0353     job = mStore->deleteCollection(collection);
0354     QVERIFY(job != nullptr);
0355     QCOMPARE(mStore->mLastCheckedJob, job);
0356     QCOMPARE(job->error(), mStore->mErrorCode);
0357     QCOMPARE(job->errorText(), mStore->mErrorText);
0358 
0359     QVERIFY(!job->exec());
0360     QVERIFY(mStore->mLastProcessedJob == nullptr);
0361     mStore->mErrorCode = 0;
0362     mStore->mErrorText = QString();
0363 }
0364 
0365 void AbstractLocalStoreTest::testFetchCollection()
0366 {
0367     Akonadi::FileStore::CollectionFetchJob *job = nullptr;
0368 
0369     // test without setPath()
0370     job = mStore->fetchCollections(Collection());
0371     QVERIFY(job != nullptr);
0372     QCOMPARE(mStore->mLastCheckedJob, job);
0373     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0374     QVERIFY(!job->errorText().isEmpty());
0375 
0376     QVERIFY(!job->exec());
0377     QVERIFY(mStore->mLastProcessedJob == nullptr);
0378 
0379     // test with path but with invalid collection
0380     mStore->setPath(QStringLiteral("/tmp/test"));
0381     job = mStore->fetchCollections(Collection());
0382     QVERIFY(job != nullptr);
0383     QCOMPARE(mStore->mLastCheckedJob, job);
0384     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0385     QVERIFY(!job->errorText().isEmpty());
0386 
0387     QVERIFY(!job->exec());
0388     QVERIFY(mStore->mLastProcessedJob == nullptr);
0389 
0390     // test with potentially valid collection (has remoteId)
0391     Collection collection;
0392     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0393     job = mStore->fetchCollections(collection);
0394     QVERIFY(job != nullptr);
0395     QCOMPARE(mStore->mLastCheckedJob, job);
0396     QCOMPARE(job->error(), 0);
0397     QVERIFY(job->errorText().isEmpty());
0398 
0399     QVERIFY(job->exec());
0400     QCOMPARE(mStore->mLastProcessedJob, job);
0401     mStore->mLastProcessedJob = nullptr;
0402 
0403     // test template check method
0404     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0405     mStore->mErrorText = KRandom::randomString(10);
0406 
0407     job = mStore->fetchCollections(collection);
0408     QVERIFY(job != nullptr);
0409     QCOMPARE(mStore->mLastCheckedJob, job);
0410     QCOMPARE(job->error(), mStore->mErrorCode);
0411     QCOMPARE(job->errorText(), mStore->mErrorText);
0412 
0413     QVERIFY(!job->exec());
0414     QVERIFY(mStore->mLastProcessedJob == nullptr);
0415     mStore->mErrorCode = 0;
0416     mStore->mErrorText = QString();
0417 
0418     // test fetch of top level collection only
0419     collection.setRemoteId(mStore->topLevelCollection().remoteId());
0420     job = mStore->fetchCollections(collection, Akonadi::FileStore::CollectionFetchJob::Base);
0421     QVERIFY(job != nullptr);
0422     QCOMPARE(mStore->mLastCheckedJob, job);
0423     QCOMPARE(job->error(), 0);
0424     QVERIFY(job->errorText().isEmpty());
0425 
0426     QVERIFY(job->exec());
0427     QVERIFY(mStore->mLastProcessedJob == nullptr); // job not handed to subclass because it is full processed in base class
0428     QCOMPARE(job->collections().count(), 1);
0429     QCOMPARE(job->collections()[0], mStore->topLevelCollection());
0430 }
0431 
0432 void AbstractLocalStoreTest::testModifyCollection()
0433 {
0434     Akonadi::FileStore::CollectionModifyJob *job = nullptr;
0435 
0436     // test without setPath()
0437     job = mStore->modifyCollection(Collection());
0438     QVERIFY(job != nullptr);
0439     QCOMPARE(mStore->mLastCheckedJob, job);
0440     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0441     QVERIFY(!job->errorText().isEmpty());
0442 
0443     QVERIFY(!job->exec());
0444     QVERIFY(mStore->mLastProcessedJob == nullptr);
0445 
0446     // test with path but with invalid item
0447     mStore->setPath(QStringLiteral("/tmp/test"));
0448     job = mStore->modifyCollection(Collection());
0449     QVERIFY(job != nullptr);
0450     QCOMPARE(mStore->mLastCheckedJob, job);
0451     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0452     QVERIFY(!job->errorText().isEmpty());
0453 
0454     QVERIFY(!job->exec());
0455     QVERIFY(mStore->mLastProcessedJob == nullptr);
0456 
0457     // test with potentially valid collection (has remoteId, but no parent remoteId)
0458     Collection collection;
0459     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0460     job = mStore->modifyCollection(collection);
0461     QVERIFY(job != nullptr);
0462     QCOMPARE(mStore->mLastCheckedJob, job);
0463     QCOMPARE(job->error(), 0);
0464     QVERIFY(job->errorText().isEmpty());
0465 
0466     QVERIFY(job->exec());
0467     QCOMPARE(mStore->mLastProcessedJob, job);
0468     mStore->mLastProcessedJob = nullptr;
0469 
0470     // test with potentially valid collection (has remoteId and parent remoteId)
0471     Collection parentCollection;
0472     parentCollection.setRemoteId(QStringLiteral("/tmp/test"));
0473     collection.setParentCollection(parentCollection);
0474     job = mStore->modifyCollection(collection);
0475     QVERIFY(job != nullptr);
0476     QCOMPARE(mStore->mLastCheckedJob, job);
0477     QCOMPARE(job->error(), 0);
0478     QVERIFY(job->errorText().isEmpty());
0479 
0480     QVERIFY(job->exec());
0481     QCOMPARE(mStore->mLastProcessedJob, job);
0482     mStore->mLastProcessedJob = nullptr;
0483 
0484     // test template check method
0485     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0486     mStore->mErrorText = KRandom::randomString(10);
0487 
0488     job = mStore->modifyCollection(collection);
0489     QVERIFY(job != nullptr);
0490     QCOMPARE(mStore->mLastCheckedJob, job);
0491     QCOMPARE(job->error(), mStore->mErrorCode);
0492     QCOMPARE(job->errorText(), mStore->mErrorText);
0493 
0494     QVERIFY(!job->exec());
0495     QVERIFY(mStore->mLastProcessedJob == nullptr);
0496 }
0497 
0498 void AbstractLocalStoreTest::testMoveCollection()
0499 {
0500     Akonadi::FileStore::CollectionMoveJob *job = nullptr;
0501 
0502     // test without setPath()
0503     job = mStore->moveCollection(Collection(), Collection());
0504     QVERIFY(job != nullptr);
0505     QCOMPARE(mStore->mLastCheckedJob, job);
0506     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0507     QVERIFY(!job->errorText().isEmpty());
0508 
0509     QVERIFY(!job->exec());
0510     QVERIFY(mStore->mLastProcessedJob == nullptr);
0511 
0512     // test with path but with invalid collections
0513     mStore->setPath(QStringLiteral("/tmp/test"));
0514     job = mStore->moveCollection(Collection(), Collection());
0515     QVERIFY(job != nullptr);
0516     QCOMPARE(mStore->mLastCheckedJob, job);
0517     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0518     QVERIFY(!job->errorText().isEmpty());
0519 
0520     QVERIFY(!job->exec());
0521     QVERIFY(mStore->mLastProcessedJob == nullptr);
0522 
0523     // test with potentially valid collection (has remoteId and parent remoteId), but invalid target parent
0524     Collection collection;
0525     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0526     Collection parentCollection;
0527     parentCollection.setRemoteId(QStringLiteral("/tmp/test"));
0528     collection.setParentCollection(parentCollection);
0529     job = mStore->moveCollection(collection, Collection());
0530     QVERIFY(job != nullptr);
0531     QCOMPARE(mStore->mLastCheckedJob, job);
0532     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0533     QVERIFY(!job->errorText().isEmpty());
0534 
0535     QVERIFY(!job->exec());
0536     QVERIFY(mStore->mLastProcessedJob == nullptr);
0537 
0538     // test with invalid parent collection, but with potentially valid collection and target parent
0539     collection.setParentCollection(Collection());
0540     job = mStore->moveCollection(collection, parentCollection);
0541     QVERIFY(job != nullptr);
0542     QCOMPARE(mStore->mLastCheckedJob, job);
0543     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0544     QVERIFY(!job->errorText().isEmpty());
0545 
0546     QVERIFY(!job->exec());
0547     QVERIFY(mStore->mLastProcessedJob == nullptr);
0548 
0549     // test with potentially valid collections
0550     Collection targetParent;
0551     targetParent.setRemoteId(QStringLiteral("/tmp/test2"));
0552     collection.setParentCollection(parentCollection);
0553     job = mStore->moveCollection(collection, targetParent);
0554     QVERIFY(job != nullptr);
0555     QCOMPARE(mStore->mLastCheckedJob, job);
0556     QCOMPARE(job->error(), 0);
0557     QVERIFY(job->errorText().isEmpty());
0558 
0559     QVERIFY(job->exec());
0560     QCOMPARE(mStore->mLastProcessedJob, job);
0561     mStore->mLastProcessedJob = nullptr;
0562 
0563     // test template check method
0564     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0565     mStore->mErrorText = KRandom::randomString(10);
0566 
0567     job = mStore->moveCollection(collection, targetParent);
0568     QVERIFY(job != nullptr);
0569     QCOMPARE(mStore->mLastCheckedJob, job);
0570     QCOMPARE(job->error(), mStore->mErrorCode);
0571     QCOMPARE(job->errorText(), mStore->mErrorText);
0572 
0573     QVERIFY(!job->exec());
0574     QVERIFY(mStore->mLastProcessedJob == nullptr);
0575 }
0576 
0577 void AbstractLocalStoreTest::testFetchItems()
0578 {
0579     Akonadi::FileStore::ItemFetchJob *job = nullptr;
0580 
0581     // test without setPath()
0582     job = mStore->fetchItems(Collection());
0583     QVERIFY(job != nullptr);
0584     QCOMPARE(mStore->mLastCheckedJob, job);
0585     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0586     QVERIFY(!job->errorText().isEmpty());
0587 
0588     QVERIFY(!job->exec());
0589     QVERIFY(mStore->mLastProcessedJob == nullptr);
0590 
0591     // test with path but with invalid collection
0592     mStore->setPath(QStringLiteral("/tmp/test"));
0593     job = mStore->fetchItems(Collection());
0594     QVERIFY(job != nullptr);
0595     QCOMPARE(mStore->mLastCheckedJob, job);
0596     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0597     QVERIFY(!job->errorText().isEmpty());
0598 
0599     QVERIFY(!job->exec());
0600     QVERIFY(mStore->mLastProcessedJob == nullptr);
0601 
0602     // test with potentially valid collection (has remoteId)
0603     Collection collection;
0604     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0605     job = mStore->fetchItems(collection);
0606     QVERIFY(job != nullptr);
0607     QCOMPARE(mStore->mLastCheckedJob, job);
0608     QCOMPARE(job->error(), 0);
0609     QVERIFY(job->errorText().isEmpty());
0610 
0611     QVERIFY(job->exec());
0612     QCOMPARE(mStore->mLastProcessedJob, job);
0613     mStore->mLastProcessedJob = nullptr;
0614 
0615     // test template check method
0616     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0617     mStore->mErrorText = KRandom::randomString(10);
0618 
0619     job = mStore->fetchItems(collection);
0620     QVERIFY(job != nullptr);
0621     QCOMPARE(mStore->mLastCheckedJob, job);
0622     QCOMPARE(job->error(), mStore->mErrorCode);
0623     QCOMPARE(job->errorText(), mStore->mErrorText);
0624 
0625     QVERIFY(!job->exec());
0626     QVERIFY(mStore->mLastProcessedJob == nullptr);
0627     mStore->mErrorCode = 0;
0628     mStore->mErrorText = QString();
0629 }
0630 
0631 void AbstractLocalStoreTest::testFetchItem()
0632 {
0633     Akonadi::FileStore::ItemFetchJob *job = nullptr;
0634 
0635     // test without setPath()
0636     job = mStore->fetchItem(Item());
0637     QVERIFY(job != nullptr);
0638     QCOMPARE(mStore->mLastCheckedJob, job);
0639     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0640     QVERIFY(!job->errorText().isEmpty());
0641 
0642     QVERIFY(!job->exec());
0643     QVERIFY(mStore->mLastProcessedJob == nullptr);
0644 
0645     // test with path but with invalid item
0646     mStore->setPath(QStringLiteral("/tmp/test"));
0647     job = mStore->fetchItem(Item());
0648     QVERIFY(job != nullptr);
0649     QCOMPARE(mStore->mLastCheckedJob, job);
0650     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0651     QVERIFY(!job->errorText().isEmpty());
0652 
0653     QVERIFY(!job->exec());
0654     QVERIFY(mStore->mLastProcessedJob == nullptr);
0655 
0656     // test with potentially valid item (has remoteId)
0657     Item item;
0658     item.setRemoteId(QStringLiteral("/tmp/test/foo"));
0659     job = mStore->fetchItem(item);
0660     QVERIFY(job != nullptr);
0661     QCOMPARE(mStore->mLastCheckedJob, job);
0662     QCOMPARE(job->error(), 0);
0663     QVERIFY(job->errorText().isEmpty());
0664 
0665     QVERIFY(job->exec());
0666     QCOMPARE(mStore->mLastProcessedJob, job);
0667     mStore->mLastProcessedJob = nullptr;
0668 
0669     // test template check method
0670     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0671     mStore->mErrorText = KRandom::randomString(10);
0672 
0673     job = mStore->fetchItem(item);
0674     QVERIFY(job != nullptr);
0675     QCOMPARE(mStore->mLastCheckedJob, job);
0676     QCOMPARE(job->error(), mStore->mErrorCode);
0677     QCOMPARE(job->errorText(), mStore->mErrorText);
0678 
0679     QVERIFY(!job->exec());
0680     QVERIFY(mStore->mLastProcessedJob == nullptr);
0681     mStore->mErrorCode = 0;
0682     mStore->mErrorText = QString();
0683 }
0684 
0685 void AbstractLocalStoreTest::testCreateItem()
0686 {
0687     Akonadi::FileStore::ItemCreateJob *job = nullptr;
0688 
0689     // test without setPath()
0690     job = mStore->createItem(Item(), Collection());
0691     QVERIFY(job != nullptr);
0692     QCOMPARE(mStore->mLastCheckedJob, job);
0693     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0694     QVERIFY(!job->errorText().isEmpty());
0695 
0696     QVERIFY(!job->exec());
0697     QVERIFY(mStore->mLastProcessedJob == nullptr);
0698 
0699     // test with path but with invalid collection
0700     mStore->setPath(QStringLiteral("/tmp/test"));
0701     job = mStore->createItem(Item(), Collection());
0702     QVERIFY(job != nullptr);
0703     QCOMPARE(mStore->mLastCheckedJob, job);
0704     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0705     QVERIFY(!job->errorText().isEmpty());
0706 
0707     QVERIFY(!job->exec());
0708     QVERIFY(mStore->mLastProcessedJob == nullptr);
0709 
0710     // test with potentially valid collection (has remoteId)
0711     Collection collection;
0712     collection.setRemoteId(QStringLiteral("/tmp/test/foo"));
0713     job = mStore->createItem(Item(), collection);
0714     QVERIFY(job != nullptr);
0715     QCOMPARE(mStore->mLastCheckedJob, job);
0716     QCOMPARE(job->error(), 0);
0717     QVERIFY(job->errorText().isEmpty());
0718 
0719     QVERIFY(job->exec());
0720     QCOMPARE(mStore->mLastProcessedJob, job);
0721     mStore->mLastProcessedJob = nullptr;
0722 
0723     // test template check method
0724     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0725     mStore->mErrorText = KRandom::randomString(10);
0726 
0727     job = mStore->createItem(Item(), collection);
0728     QVERIFY(job != nullptr);
0729     QCOMPARE(mStore->mLastCheckedJob, job);
0730     QCOMPARE(job->error(), mStore->mErrorCode);
0731     QCOMPARE(job->errorText(), mStore->mErrorText);
0732 
0733     QVERIFY(!job->exec());
0734     QVERIFY(mStore->mLastProcessedJob == nullptr);
0735     mStore->mErrorCode = 0;
0736     mStore->mErrorText = QString();
0737 }
0738 
0739 void AbstractLocalStoreTest::testDeleteItem()
0740 {
0741     Akonadi::FileStore::ItemDeleteJob *job = nullptr;
0742 
0743     // test without setPath()
0744     job = mStore->deleteItem(Item());
0745     QVERIFY(job != nullptr);
0746     QCOMPARE(mStore->mLastCheckedJob, job);
0747     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0748     QVERIFY(!job->errorText().isEmpty());
0749 
0750     QVERIFY(!job->exec());
0751     QVERIFY(mStore->mLastProcessedJob == nullptr);
0752 
0753     // test with path but with invalid item
0754     mStore->setPath(QStringLiteral("/tmp/test"));
0755     job = mStore->deleteItem(Item());
0756     QVERIFY(job != nullptr);
0757     QCOMPARE(mStore->mLastCheckedJob, job);
0758     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0759     QVERIFY(!job->errorText().isEmpty());
0760 
0761     QVERIFY(!job->exec());
0762     QVERIFY(mStore->mLastProcessedJob == nullptr);
0763 
0764     // test with potentially valid item (has remoteId)
0765     Item item;
0766     item.setRemoteId(QStringLiteral("/tmp/test/foo"));
0767     job = mStore->deleteItem(item);
0768     QVERIFY(job != nullptr);
0769     QCOMPARE(mStore->mLastCheckedJob, job);
0770     QCOMPARE(job->error(), 0);
0771     QVERIFY(job->errorText().isEmpty());
0772 
0773     QVERIFY(job->exec());
0774     QCOMPARE(mStore->mLastProcessedJob, job);
0775     mStore->mLastProcessedJob = nullptr;
0776 
0777     // test template check method
0778     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0779     mStore->mErrorText = KRandom::randomString(10);
0780 
0781     job = mStore->deleteItem(item);
0782     QVERIFY(job != nullptr);
0783     QCOMPARE(mStore->mLastCheckedJob, job);
0784     QCOMPARE(job->error(), mStore->mErrorCode);
0785     QCOMPARE(job->errorText(), mStore->mErrorText);
0786 
0787     QVERIFY(!job->exec());
0788     QVERIFY(mStore->mLastProcessedJob == nullptr);
0789     mStore->mErrorCode = 0;
0790     mStore->mErrorText = QString();
0791 }
0792 
0793 void AbstractLocalStoreTest::testModifyItem()
0794 {
0795     Akonadi::FileStore::ItemModifyJob *job = nullptr;
0796 
0797     // test without setPath()
0798     job = mStore->modifyItem(Item());
0799     QVERIFY(job != nullptr);
0800     QCOMPARE(mStore->mLastCheckedJob, job);
0801     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0802     QVERIFY(!job->errorText().isEmpty());
0803 
0804     QVERIFY(!job->exec());
0805     QVERIFY(mStore->mLastProcessedJob == nullptr);
0806 
0807     // test with path but with invalid item
0808     mStore->setPath(QStringLiteral("/tmp/test"));
0809     job = mStore->modifyItem(Item());
0810     QVERIFY(job != nullptr);
0811     QCOMPARE(mStore->mLastCheckedJob, job);
0812     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0813     QVERIFY(!job->errorText().isEmpty());
0814 
0815     QVERIFY(!job->exec());
0816     QVERIFY(mStore->mLastProcessedJob == nullptr);
0817 
0818     // test with potentially valid item (has remoteId)
0819     Item item;
0820     item.setRemoteId(QStringLiteral("/tmp/test/foo"));
0821     job = mStore->modifyItem(item);
0822     QVERIFY(job != nullptr);
0823     QCOMPARE(mStore->mLastCheckedJob, job);
0824     QCOMPARE(job->error(), 0);
0825     QVERIFY(job->errorText().isEmpty());
0826 
0827     QVERIFY(job->exec());
0828     QCOMPARE(mStore->mLastProcessedJob, job);
0829     mStore->mLastProcessedJob = nullptr;
0830 
0831     // test template check method
0832     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0833     mStore->mErrorText = KRandom::randomString(10);
0834 
0835     job = mStore->modifyItem(item);
0836     QVERIFY(job != nullptr);
0837     QCOMPARE(mStore->mLastCheckedJob, job);
0838     QCOMPARE(job->error(), mStore->mErrorCode);
0839     QCOMPARE(job->errorText(), mStore->mErrorText);
0840 
0841     QVERIFY(!job->exec());
0842     QVERIFY(mStore->mLastProcessedJob == nullptr);
0843 }
0844 
0845 void AbstractLocalStoreTest::testMoveItem()
0846 {
0847     Akonadi::FileStore::ItemMoveJob *job = nullptr;
0848 
0849     // test without setPath()
0850     job = mStore->moveItem(Item(), Collection());
0851     QVERIFY(job != nullptr);
0852     QCOMPARE(mStore->mLastCheckedJob, job);
0853     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0854     QVERIFY(!job->errorText().isEmpty());
0855 
0856     QVERIFY(!job->exec());
0857     QVERIFY(mStore->mLastProcessedJob == nullptr);
0858 
0859     // test with path but with invalid item and collection
0860     mStore->setPath(QStringLiteral("/tmp/test"));
0861     job = mStore->moveItem(Item(), Collection());
0862     QVERIFY(job != nullptr);
0863     QCOMPARE(mStore->mLastCheckedJob, job);
0864     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0865     QVERIFY(!job->errorText().isEmpty());
0866 
0867     QVERIFY(!job->exec());
0868     QVERIFY(mStore->mLastProcessedJob == nullptr);
0869 
0870     // test with potentially valid item (has remoteId and parent remoteId), but invalid target parent
0871     Item item;
0872     item.setRemoteId(QStringLiteral("/tmp/test/foo"));
0873     Collection parentCollection;
0874     parentCollection.setRemoteId(QStringLiteral("/tmp/test"));
0875     item.setParentCollection(parentCollection);
0876     job = mStore->moveItem(item, Collection());
0877     QVERIFY(job != nullptr);
0878     QCOMPARE(mStore->mLastCheckedJob, job);
0879     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0880     QVERIFY(!job->errorText().isEmpty());
0881 
0882     QVERIFY(!job->exec());
0883     QVERIFY(mStore->mLastProcessedJob == nullptr);
0884 
0885     // test with invalid parent collection, but with potentially valid item and target parent
0886     item.setParentCollection(Collection());
0887     job = mStore->moveItem(item, parentCollection);
0888     QVERIFY(job != nullptr);
0889     QCOMPARE(mStore->mLastCheckedJob, job);
0890     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidJobContext);
0891     QVERIFY(!job->errorText().isEmpty());
0892 
0893     QVERIFY(!job->exec());
0894     QVERIFY(mStore->mLastProcessedJob == nullptr);
0895 
0896     // test with potentially valid item and collections
0897     Collection targetParent;
0898     targetParent.setRemoteId(QStringLiteral("/tmp/test2"));
0899     item.setParentCollection(parentCollection);
0900     job = mStore->moveItem(item, targetParent);
0901     QVERIFY(job != nullptr);
0902     QCOMPARE(mStore->mLastCheckedJob, job);
0903     QCOMPARE(job->error(), 0);
0904     QVERIFY(job->errorText().isEmpty());
0905 
0906     QVERIFY(job->exec());
0907     QCOMPARE(mStore->mLastProcessedJob, job);
0908     mStore->mLastProcessedJob = nullptr;
0909 
0910     // test template check method
0911     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0912     mStore->mErrorText = KRandom::randomString(10);
0913 
0914     job = mStore->moveItem(item, targetParent);
0915     QVERIFY(job != nullptr);
0916     QCOMPARE(mStore->mLastCheckedJob, job);
0917     QCOMPARE(job->error(), mStore->mErrorCode);
0918     QCOMPARE(job->errorText(), mStore->mErrorText);
0919 
0920     QVERIFY(!job->exec());
0921     QVERIFY(mStore->mLastProcessedJob == nullptr);
0922 }
0923 
0924 void AbstractLocalStoreTest::testCompactStore()
0925 {
0926     Akonadi::FileStore::StoreCompactJob *job = nullptr;
0927 
0928     // test without setPath()
0929     job = mStore->compactStore();
0930     QVERIFY(job != nullptr);
0931     QCOMPARE(mStore->mLastCheckedJob, job);
0932     QCOMPARE(job->error(), (int)Akonadi::FileStore::Job::InvalidStoreState);
0933     QVERIFY(!job->errorText().isEmpty());
0934 
0935     QVERIFY(!job->exec());
0936     QVERIFY(mStore->mLastProcessedJob == nullptr);
0937 
0938     // test with path
0939     mStore->setPath(QStringLiteral("/tmp/test"));
0940     job = mStore->compactStore();
0941     QVERIFY(job != nullptr);
0942     QCOMPARE(mStore->mLastCheckedJob, job);
0943     QCOMPARE(job->error(), 0);
0944     QVERIFY(job->errorText().isEmpty());
0945 
0946     QVERIFY(job->exec());
0947     QCOMPARE(mStore->mLastProcessedJob, job);
0948     mStore->mLastProcessedJob = nullptr;
0949 
0950     // test template check method
0951     mStore->mErrorCode = QRandomGenerator::global()->generate() + 1;
0952     mStore->mErrorText = KRandom::randomString(10);
0953 
0954     job = mStore->compactStore();
0955     QVERIFY(job != nullptr);
0956     QCOMPARE(mStore->mLastCheckedJob, job);
0957     QCOMPARE(job->error(), mStore->mErrorCode);
0958     QCOMPARE(job->errorText(), mStore->mErrorText);
0959 
0960     QVERIFY(!job->exec());
0961     QVERIFY(mStore->mLastProcessedJob == nullptr);
0962     mStore->mErrorCode = 0;
0963     mStore->mErrorText = QString();
0964 }
0965 
0966 QTEST_MAIN(AbstractLocalStoreTest)
0967 
0968 #include "abstractlocalstoretest.moc"