File indexing completed on 2024-12-22 04:57:36

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 "mixedmaildirstore.h"
0009 
0010 #include "testdatautil.h"
0011 
0012 #include "filestore/collectionmovejob.h"
0013 #include "filestore/itemfetchjob.h"
0014 
0015 #include "libmaildir/maildir.h"
0016 
0017 #include <QTemporaryDir>
0018 
0019 #include <QDir>
0020 #include <QFileInfo>
0021 #include <QTest>
0022 
0023 using namespace Akonadi;
0024 
0025 class CollectionMoveTest : public QObject
0026 {
0027     Q_OBJECT
0028 
0029 public:
0030     CollectionMoveTest()
0031         : QObject()
0032         , mStore(nullptr)
0033         , mDir(nullptr)
0034     {
0035     }
0036 
0037     ~CollectionMoveTest() override
0038     {
0039         delete mStore;
0040         delete mDir;
0041     }
0042 
0043 private:
0044     MixedMaildirStore *mStore = nullptr;
0045     QTemporaryDir *mDir = nullptr;
0046 
0047 private Q_SLOTS:
0048     void init();
0049     void cleanup();
0050     void testMoveToTopLevel();
0051     void testMoveToMaildir();
0052     void testMoveToMBox();
0053 };
0054 
0055 void CollectionMoveTest::init()
0056 {
0057     mStore = new MixedMaildirStore;
0058 
0059     mDir = new QTemporaryDir;
0060     QVERIFY(mDir->isValid());
0061     QVERIFY(QDir(mDir->path()).exists());
0062 }
0063 
0064 void CollectionMoveTest::cleanup()
0065 {
0066     delete mStore;
0067     mStore = nullptr;
0068     delete mDir;
0069     mDir = nullptr;
0070 }
0071 
0072 void CollectionMoveTest::testMoveToTopLevel()
0073 {
0074     QDir topDir(mDir->path());
0075 
0076     // top level dir
0077     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), topDir.path(), QStringLiteral("collection1")));
0078     // QFileInfo fileInfo1(topDir, QStringLiteral("collection1"));
0079     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection2")));
0080     // QFileInfo fileInfo2(topDir, QStringLiteral("collection2"));
0081 
0082     // first level maildir parent
0083     QDir subDir1 = topDir;
0084     QVERIFY(subDir1.mkdir(QStringLiteral(".collection1.directory")));
0085     QVERIFY(subDir1.cd(QStringLiteral(".collection1.directory")));
0086     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir1.path(), QStringLiteral("collection1_1")));
0087     QFileInfo fileInfo1_1(subDir1.path(), QStringLiteral("collection1_1"));
0088     QVERIFY(fileInfo1_1.exists());
0089     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir1.path(), QStringLiteral("collection1_2")));
0090     QFileInfo fileInfo1_2(subDir1.path(), QStringLiteral("collection1_2"));
0091     QVERIFY(fileInfo1_2.exists());
0092 
0093     // first level mbox parent
0094     QDir subDir2 = topDir;
0095     QVERIFY(subDir2.mkdir(QStringLiteral(".collection2.directory")));
0096     QVERIFY(subDir2.cd(QStringLiteral(".collection2.directory")));
0097     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir2.path(), QStringLiteral("collection2_1")));
0098     QFileInfo fileInfo2_1(subDir2.path(), QStringLiteral("collection2_1"));
0099     QVERIFY(fileInfo2_1.exists());
0100     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir2.path(), QStringLiteral("collection2_2")));
0101     QFileInfo fileInfo2_2(subDir2.path(), QStringLiteral("collection2_2"));
0102     QVERIFY(fileInfo2_2.exists());
0103 
0104     mStore->setPath(topDir.path());
0105 
0106     // common variables
0107     FileStore::CollectionMoveJob *job = nullptr;
0108     FileStore::ItemFetchJob *itemFetch = nullptr;
0109     Collection collection;
0110     const QVariant colListVar = QVariant::fromValue<Collection::List>(Collection::List());
0111     QVariant var;
0112     Collection::List collections;
0113     Item::List items;
0114     QMap<QByteArray, int> flagCounts;
0115 
0116     // test moving maildir from maildir parent
0117     Collection collection1;
0118     collection1.setName(QStringLiteral("collection1"));
0119     collection1.setRemoteId(QStringLiteral("collection1"));
0120     collection1.setParentCollection(mStore->topLevelCollection());
0121 
0122     Collection collection1_1;
0123     collection1_1.setName(QStringLiteral("collection1_1"));
0124     collection1_1.setRemoteId(QStringLiteral("collection1_1"));
0125     collection1_1.setParentCollection(collection1);
0126 
0127     job = mStore->moveCollection(collection1_1, mStore->topLevelCollection());
0128 
0129     QVERIFY(job->exec());
0130     QCOMPARE(job->error(), 0);
0131 
0132     collection = job->collection();
0133     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
0134     QCOMPARE(collection.parentCollection(), mStore->topLevelCollection());
0135 
0136     fileInfo1_1.refresh();
0137     QVERIFY(!fileInfo1_1.exists());
0138     fileInfo1_1 = QFileInfo(topDir.path(), collection.remoteId());
0139     QVERIFY(fileInfo1_1.exists());
0140 
0141     // check for index preservation
0142     var = job->property("onDiskIndexInvalidated");
0143     QVERIFY(var.isValid());
0144     QCOMPARE(var.userType(), colListVar.userType());
0145 
0146     collections = var.value<Collection::List>();
0147     QCOMPARE((int)collections.count(), 1);
0148     QCOMPARE(collections.first(), collection);
0149 
0150     // get the items and check the flags (see data/README)
0151     itemFetch = mStore->fetchItems(collection);
0152     QVERIFY(itemFetch->exec());
0153     QCOMPARE(itemFetch->error(), 0);
0154 
0155     items = itemFetch->items();
0156     QCOMPARE((int)items.count(), 4);
0157     for (const Item &item : std::as_const(items)) {
0158         const auto flags = item.flags();
0159         for (const QByteArray &flag : flags) {
0160             ++flagCounts[flag];
0161         }
0162     }
0163 
0164     QCOMPARE(flagCounts["\\SEEN"], 2);
0165     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0166     QCOMPARE(flagCounts["$TODO"], 1);
0167     flagCounts.clear();
0168 
0169     // test moving mbox from maildir parent
0170     Collection collection1_2;
0171     collection1_2.setName(QStringLiteral("collection1_2"));
0172     collection1_2.setRemoteId(QStringLiteral("collection1_2"));
0173     collection1_2.setParentCollection(collection1);
0174 
0175     job = mStore->moveCollection(collection1_2, mStore->topLevelCollection());
0176 
0177     QVERIFY(job->exec());
0178     QCOMPARE(job->error(), 0);
0179 
0180     collection = job->collection();
0181     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
0182     QCOMPARE(collection.parentCollection(), mStore->topLevelCollection());
0183 
0184     fileInfo1_2.refresh();
0185     QVERIFY(!fileInfo1_2.exists());
0186     fileInfo1_2 = QFileInfo(topDir.path(), collection.remoteId());
0187     QVERIFY(fileInfo1_2.exists());
0188 
0189     // check for index preservation
0190     var = job->property("onDiskIndexInvalidated");
0191     QVERIFY(var.isValid());
0192     QCOMPARE(var.userType(), colListVar.userType());
0193 
0194     collections = var.value<Collection::List>();
0195     QCOMPARE((int)collections.count(), 1);
0196     QCOMPARE(collections.first(), collection);
0197 
0198     // get the items and check the flags (see data/README)
0199     itemFetch = mStore->fetchItems(collection);
0200     QVERIFY(itemFetch->exec());
0201     QCOMPARE(itemFetch->error(), 0);
0202 
0203     items = itemFetch->items();
0204     QCOMPARE((int)items.count(), 4);
0205     for (const Item &item : std::as_const(items)) {
0206         const auto flags = item.flags();
0207         for (const QByteArray &flag : flags) {
0208             ++flagCounts[flag];
0209         }
0210     }
0211 
0212     QCOMPARE(flagCounts["\\SEEN"], 2);
0213     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0214     QCOMPARE(flagCounts["$TODO"], 1);
0215     flagCounts.clear();
0216 
0217     // test moving mbox from mbox parent
0218     Collection collection2;
0219     collection2.setName(QStringLiteral("collection2"));
0220     collection2.setRemoteId(QStringLiteral("collection2"));
0221     collection2.setParentCollection(mStore->topLevelCollection());
0222 
0223     Collection collection2_1;
0224     collection2_1.setName(QStringLiteral("collection2_1"));
0225     collection2_1.setRemoteId(QStringLiteral("collection2_1"));
0226     collection2_1.setParentCollection(collection2);
0227 
0228     job = mStore->moveCollection(collection2_1, mStore->topLevelCollection());
0229 
0230     QVERIFY(job->exec());
0231     QCOMPARE(job->error(), 0);
0232 
0233     collection = job->collection();
0234     QCOMPARE(collection.remoteId(), collection2_1.remoteId());
0235     QCOMPARE(collection.parentCollection(), mStore->topLevelCollection());
0236 
0237     fileInfo2_1.refresh();
0238     QVERIFY(!fileInfo2_1.exists());
0239     fileInfo2_1 = QFileInfo(topDir.path(), collection.remoteId());
0240     QVERIFY(fileInfo2_1.exists());
0241 
0242     // check for index preservation
0243     var = job->property("onDiskIndexInvalidated");
0244     QVERIFY(var.isValid());
0245     QCOMPARE(var.userType(), colListVar.userType());
0246 
0247     collections = var.value<Collection::List>();
0248     QCOMPARE((int)collections.count(), 1);
0249     QCOMPARE(collections.first(), collection);
0250 
0251     // get the items and check the flags (see data/README)
0252     itemFetch = mStore->fetchItems(collection);
0253     QVERIFY(itemFetch->exec());
0254     QCOMPARE(itemFetch->error(), 0);
0255 
0256     items = itemFetch->items();
0257     QCOMPARE((int)items.count(), 4);
0258     for (const Item &item : std::as_const(items)) {
0259         const auto flags = item.flags();
0260         for (const QByteArray &flag : flags) {
0261             ++flagCounts[flag];
0262         }
0263     }
0264 
0265     QCOMPARE(flagCounts["\\SEEN"], 2);
0266     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0267     QCOMPARE(flagCounts["$TODO"], 1);
0268     flagCounts.clear();
0269 
0270     // test moving maildir from mbox parent
0271     Collection collection2_2;
0272     collection2_2.setName(QStringLiteral("collection2_2"));
0273     collection2_2.setRemoteId(QStringLiteral("collection2_2"));
0274     collection2_2.setParentCollection(collection2);
0275 
0276     job = mStore->moveCollection(collection2_2, mStore->topLevelCollection());
0277 
0278     QVERIFY(job->exec());
0279     QCOMPARE(job->error(), 0);
0280 
0281     collection = job->collection();
0282     QCOMPARE(collection.remoteId(), collection2_2.remoteId());
0283     QCOMPARE(collection.parentCollection(), mStore->topLevelCollection());
0284 
0285     fileInfo2_2.refresh();
0286     QVERIFY(!fileInfo2_2.exists());
0287     fileInfo2_2 = QFileInfo(topDir.path(), collection.remoteId());
0288     QVERIFY(fileInfo2_2.exists());
0289 
0290     // check for index preservation
0291     var = job->property("onDiskIndexInvalidated");
0292     QVERIFY(var.isValid());
0293     QCOMPARE(var.userType(), colListVar.userType());
0294 
0295     collections = var.value<Collection::List>();
0296     QCOMPARE((int)collections.count(), 1);
0297     QCOMPARE(collections.first(), collection);
0298 
0299     // get the items and check the flags (see data/README)
0300     itemFetch = mStore->fetchItems(collection);
0301     QVERIFY(itemFetch->exec());
0302     QCOMPARE(itemFetch->error(), 0);
0303 
0304     items = itemFetch->items();
0305     QCOMPARE((int)items.count(), 4);
0306     for (const Item &item : std::as_const(items)) {
0307         const auto flags = item.flags();
0308         for (const QByteArray &flag : flags) {
0309             ++flagCounts[flag];
0310         }
0311     }
0312 
0313     QCOMPARE(flagCounts["\\SEEN"], 2);
0314     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0315     QCOMPARE(flagCounts["$TODO"], 1);
0316     flagCounts.clear();
0317 }
0318 
0319 void CollectionMoveTest::testMoveToMaildir()
0320 {
0321     QDir topDir(mDir->path());
0322 
0323     // top level dir
0324     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), topDir.path(), QStringLiteral("collection1")));
0325     QFileInfo fileInfo1(topDir, QStringLiteral("collection1"));
0326     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), topDir.path(), QStringLiteral("collection2")));
0327     QFileInfo fileInfo2(topDir, QStringLiteral("collection2"));
0328     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection3")));
0329     QFileInfo fileInfo3(topDir, QStringLiteral("collection3"));
0330     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection4")));
0331     QFileInfo fileInfo4(topDir, QStringLiteral("collection4"));
0332 
0333     // first level maildir parent
0334     QDir subDir1 = topDir;
0335     QVERIFY(subDir1.mkdir(QStringLiteral(".collection1.directory")));
0336     QVERIFY(subDir1.cd(QStringLiteral(".collection1.directory")));
0337     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir1.path(), QStringLiteral("collection1_1")));
0338     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir1.path(), QStringLiteral("collection1_2")));
0339 
0340     // first level mbox parent
0341     QDir subDir4 = topDir;
0342     QVERIFY(subDir4.mkdir(QStringLiteral(".collection4.directory")));
0343     QVERIFY(subDir4.cd(QStringLiteral(".collection4.directory")));
0344     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir4.path(), QStringLiteral("collection4_1")));
0345     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir4.path(), QStringLiteral("collection4_2")));
0346     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir4.path(), QStringLiteral("collection4_3")));
0347     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir4.path(), QStringLiteral("collection4_4")));
0348 
0349     // target maildir
0350     KPIM::Maildir topLevelMd(topDir.path(), true);
0351     KPIM::Maildir targetMd(topLevelMd.addSubFolder(QStringLiteral("target")), false);
0352     QVERIFY(targetMd.isValid());
0353     QDir subDirTarget;
0354 
0355     mStore->setPath(topDir.path());
0356 
0357     // common variables
0358     FileStore::CollectionMoveJob *job = nullptr;
0359     FileStore::ItemFetchJob *itemFetch = nullptr;
0360     Collection collection;
0361     const QVariant colListVar = QVariant::fromValue<Collection::List>(Collection::List());
0362     QVariant var;
0363     Collection::List collections;
0364     Item::List items;
0365     QMap<QByteArray, int> flagCounts;
0366 
0367     Collection target;
0368     target.setName(QStringLiteral("target"));
0369     target.setRemoteId(QStringLiteral("target"));
0370     target.setParentCollection(mStore->topLevelCollection());
0371 
0372     // test move leaf maildir into sibling
0373     Collection collection2;
0374     collection2.setName(QStringLiteral("collection2"));
0375     collection2.setRemoteId(QStringLiteral("collection2"));
0376     collection2.setParentCollection(mStore->topLevelCollection());
0377 
0378     job = mStore->moveCollection(collection2, target);
0379 
0380     QVERIFY(job->exec());
0381     QCOMPARE(job->error(), 0);
0382 
0383     subDirTarget = topDir;
0384     QVERIFY(subDirTarget.cd(QStringLiteral(".target.directory")));
0385 
0386     collection = job->collection();
0387     QCOMPARE(collection.remoteId(), collection2.remoteId());
0388     QCOMPARE(collection.parentCollection(), target);
0389 
0390     fileInfo2.refresh();
0391     QVERIFY(!fileInfo2.exists());
0392     fileInfo2 = QFileInfo(subDirTarget, collection.remoteId());
0393     QVERIFY(fileInfo2.exists());
0394 
0395     // check for index preservation
0396     var = job->property("onDiskIndexInvalidated");
0397     QVERIFY(var.isValid());
0398     QCOMPARE(var.userType(), colListVar.userType());
0399 
0400     collections = var.value<Collection::List>();
0401     QCOMPARE((int)collections.count(), 1);
0402     QCOMPARE(collections.first(), collection);
0403 
0404     // get the items and check the flags (see data/README)
0405     itemFetch = mStore->fetchItems(collection);
0406     QVERIFY(itemFetch->exec());
0407     QCOMPARE(itemFetch->error(), 0);
0408 
0409     items = itemFetch->items();
0410     QCOMPARE((int)items.count(), 4);
0411     for (const Item &item : std::as_const(items)) {
0412         const auto flags{item.flags()};
0413         for (const QByteArray &flag : flags) {
0414             ++flagCounts[flag];
0415         }
0416     }
0417 
0418     QCOMPARE(flagCounts["\\SEEN"], 2);
0419     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0420     QCOMPARE(flagCounts["$TODO"], 1);
0421     flagCounts.clear();
0422 
0423     // test move leaf mbox into sibling
0424     Collection collection3;
0425     collection3.setName(QStringLiteral("collection3"));
0426     collection3.setRemoteId(QStringLiteral("collection3"));
0427     collection3.setParentCollection(mStore->topLevelCollection());
0428 
0429     job = mStore->moveCollection(collection3, target);
0430 
0431     QVERIFY(job->exec());
0432     QCOMPARE(job->error(), 0);
0433 
0434     collection = job->collection();
0435     QCOMPARE(collection.remoteId(), collection3.remoteId());
0436     QCOMPARE(collection.parentCollection(), target);
0437 
0438     fileInfo3.refresh();
0439     QVERIFY(!fileInfo3.exists());
0440     fileInfo3 = QFileInfo(subDirTarget, collection.remoteId());
0441     QVERIFY(fileInfo3.exists());
0442 
0443     // check for index preservation
0444     var = job->property("onDiskIndexInvalidated");
0445     QVERIFY(var.isValid());
0446     QCOMPARE(var.userType(), colListVar.userType());
0447 
0448     collections = var.value<Collection::List>();
0449     QCOMPARE((int)collections.count(), 1);
0450     QCOMPARE(collections.first(), collection);
0451 
0452     // get the items and check the flags (see data/README)
0453     itemFetch = mStore->fetchItems(collection);
0454     QVERIFY(itemFetch->exec());
0455     QCOMPARE(itemFetch->error(), 0);
0456 
0457     items = itemFetch->items();
0458     QCOMPARE((int)items.count(), 4);
0459     for (const Item &item : std::as_const(items)) {
0460         const auto flags = item.flags();
0461         for (const QByteArray &flag : flags) {
0462             ++flagCounts[flag];
0463         }
0464     }
0465 
0466     QCOMPARE(flagCounts["\\SEEN"], 2);
0467     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0468     QCOMPARE(flagCounts["$TODO"], 1);
0469     flagCounts.clear();
0470 
0471     // test move maildir with subtree into sibling
0472     Collection collection1;
0473     collection1.setName(QStringLiteral("collection1"));
0474     collection1.setRemoteId(QStringLiteral("collection1"));
0475     collection1.setParentCollection(mStore->topLevelCollection());
0476 
0477     // load sub collection index data to check for correct cache updates
0478     Collection collection1_1;
0479     collection1_1.setName(QStringLiteral("collection1_1"));
0480     collection1_1.setRemoteId(QStringLiteral("collection1_1"));
0481     collection1_1.setParentCollection(collection1);
0482     itemFetch = mStore->fetchItems(collection1_1);
0483     QVERIFY(itemFetch->exec());
0484 
0485     Collection collection1_2;
0486     collection1_2.setName(QStringLiteral("collection1_2"));
0487     collection1_2.setRemoteId(QStringLiteral("collection1_2"));
0488     collection1_2.setParentCollection(collection1);
0489     itemFetch = mStore->fetchItems(collection1_2);
0490     QVERIFY(itemFetch->exec());
0491 
0492     job = mStore->moveCollection(collection1, target);
0493 
0494     QVERIFY(job->exec());
0495     QCOMPARE(job->error(), 0);
0496 
0497     collection = job->collection();
0498     QCOMPARE(collection.remoteId(), collection1.remoteId());
0499     QCOMPARE(collection.parentCollection(), target);
0500 
0501     fileInfo1.refresh();
0502     QVERIFY(!fileInfo1.exists());
0503     fileInfo1 = QFileInfo(subDirTarget, collection.remoteId());
0504     QVERIFY(fileInfo1.exists());
0505     QVERIFY(!subDir1.exists());
0506     subDir1 = subDirTarget;
0507     QVERIFY(subDir1.cd(QStringLiteral(".collection1.directory")));
0508     QCOMPARE(subDir1.entryList(QStringList() << QStringLiteral("collection*")),
0509              QStringList() << QStringLiteral("collection1_1") << QStringLiteral("collection1_2"));
0510 
0511     // check for index preservation
0512     var = job->property("onDiskIndexInvalidated");
0513     QVERIFY(var.isValid());
0514     QCOMPARE(var.userType(), colListVar.userType());
0515 
0516     collections = var.value<Collection::List>();
0517     QCOMPARE((int)collections.count(), 1);
0518     QCOMPARE(collections.first(), collection);
0519 
0520     // get the items and check the flags (see data/README)
0521     itemFetch = mStore->fetchItems(collection);
0522     QVERIFY(itemFetch->exec());
0523     QCOMPARE(itemFetch->error(), 0);
0524 
0525     items = itemFetch->items();
0526     QCOMPARE((int)items.count(), 4);
0527     for (const Item &item : std::as_const(items)) {
0528         const auto flags{item.flags()};
0529         for (const QByteArray &flag : flags) {
0530             ++flagCounts[flag];
0531         }
0532     }
0533 
0534     QCOMPARE(flagCounts["\\SEEN"], 2);
0535     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0536     QCOMPARE(flagCounts["$TODO"], 1);
0537     flagCounts.clear();
0538 
0539     // check for children cache path updates
0540     collection1.setParentCollection(target);
0541     collection1_1.setParentCollection(collection1);
0542     collection1_2.setParentCollection(collection1);
0543 
0544     itemFetch = mStore->fetchItems(collection1_1);
0545     QVERIFY(itemFetch->exec());
0546     QCOMPARE(itemFetch->error(), 0);
0547 
0548     items = itemFetch->items();
0549     QCOMPARE((int)items.count(), 4);
0550     for (const Item &item : std::as_const(items)) {
0551         const auto flags = item.flags();
0552         for (const QByteArray &flag : flags) {
0553             ++flagCounts[flag];
0554         }
0555     }
0556 
0557     QCOMPARE(flagCounts["\\SEEN"], 2);
0558     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0559     QCOMPARE(flagCounts["$TODO"], 1);
0560     flagCounts.clear();
0561 
0562     itemFetch = mStore->fetchItems(collection1_2);
0563     QVERIFY(itemFetch->exec());
0564     QCOMPARE(itemFetch->error(), 0);
0565 
0566     items = itemFetch->items();
0567     QCOMPARE((int)items.count(), 4);
0568     for (const Item &item : std::as_const(items)) {
0569         const auto flags{item.flags()};
0570         for (const QByteArray &flag : flags) {
0571             ++flagCounts[flag];
0572         }
0573     }
0574 
0575     QCOMPARE(flagCounts["\\SEEN"], 2);
0576     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0577     QCOMPARE(flagCounts["$TODO"], 1);
0578     flagCounts.clear();
0579 
0580     // test move mbox with subtree into sibling
0581     Collection collection4;
0582     collection4.setName(QStringLiteral("collection4"));
0583     collection4.setRemoteId(QStringLiteral("collection4"));
0584     collection4.setParentCollection(mStore->topLevelCollection());
0585 
0586     // load sub collection index data to check for correct cache updates
0587     Collection collection4_1;
0588     collection4_1.setName(QStringLiteral("collection4_1"));
0589     collection4_1.setRemoteId(QStringLiteral("collection4_1"));
0590     collection4_1.setParentCollection(collection4);
0591     itemFetch = mStore->fetchItems(collection4_1);
0592     QVERIFY(itemFetch->exec());
0593 
0594     Collection collection4_2;
0595     collection4_2.setName(QStringLiteral("collection4_2"));
0596     collection4_2.setRemoteId(QStringLiteral("collection4_2"));
0597     collection4_2.setParentCollection(collection4);
0598     itemFetch = mStore->fetchItems(collection4_2);
0599     QVERIFY(itemFetch->exec());
0600 
0601     job = mStore->moveCollection(collection4, target);
0602 
0603     QVERIFY(job->exec());
0604     QCOMPARE(job->error(), 0);
0605 
0606     collection = job->collection();
0607     QCOMPARE(collection.remoteId(), collection4.remoteId());
0608     QCOMPARE(collection.parentCollection(), target);
0609 
0610     fileInfo4.refresh();
0611     QVERIFY(!fileInfo4.exists());
0612     fileInfo4 = QFileInfo(subDirTarget, collection.remoteId());
0613     QVERIFY(fileInfo4.exists());
0614     QVERIFY(!subDir4.exists());
0615     subDir4 = subDirTarget;
0616     QVERIFY(subDir4.cd(QStringLiteral(".collection4.directory")));
0617     QCOMPARE(subDir4.entryList(QStringList() << QStringLiteral("collection*")),
0618              QStringList() << QStringLiteral("collection4_1") << QStringLiteral("collection4_2") << QStringLiteral("collection4_3")
0619                            << QStringLiteral("collection4_4"));
0620 
0621     // check for index preservation
0622     var = job->property("onDiskIndexInvalidated");
0623     QVERIFY(var.isValid());
0624     QCOMPARE(var.userType(), colListVar.userType());
0625 
0626     collections = var.value<Collection::List>();
0627     QCOMPARE((int)collections.count(), 1);
0628     QCOMPARE(collections.first(), collection);
0629 
0630     // get the items and check the flags (see data/README)
0631     itemFetch = mStore->fetchItems(collection);
0632     QVERIFY(itemFetch->exec());
0633     QCOMPARE(itemFetch->error(), 0);
0634 
0635     items = itemFetch->items();
0636     QCOMPARE((int)items.count(), 4);
0637     for (const Item &item : std::as_const(items)) {
0638         const auto flags = item.flags();
0639         for (const QByteArray &flag : flags) {
0640             ++flagCounts[flag];
0641         }
0642     }
0643 
0644     QCOMPARE(flagCounts["\\SEEN"], 2);
0645     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0646     QCOMPARE(flagCounts["$TODO"], 1);
0647     flagCounts.clear();
0648 
0649     // check for children cache path updates
0650     collection4.setParentCollection(target);
0651     collection4_1.setParentCollection(collection4);
0652     collection4_2.setParentCollection(collection4);
0653 
0654     itemFetch = mStore->fetchItems(collection4_1);
0655     QVERIFY(itemFetch->exec());
0656     QCOMPARE(itemFetch->error(), 0);
0657 
0658     items = itemFetch->items();
0659     QCOMPARE((int)items.count(), 4);
0660     for (const Item &item : std::as_const(items)) {
0661         const auto flags{item.flags()};
0662         for (const QByteArray &flag : flags) {
0663             ++flagCounts[flag];
0664         }
0665     }
0666 
0667     QCOMPARE(flagCounts["\\SEEN"], 2);
0668     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0669     QCOMPARE(flagCounts["$TODO"], 1);
0670     flagCounts.clear();
0671 
0672     itemFetch = mStore->fetchItems(collection4_2);
0673     QVERIFY(itemFetch->exec());
0674     QCOMPARE(itemFetch->error(), 0);
0675 
0676     items = itemFetch->items();
0677     QCOMPARE((int)items.count(), 4);
0678     for (const Item &item : std::as_const(items)) {
0679         const auto flags = item.flags();
0680         for (const QByteArray &flag : flags) {
0681             ++flagCounts[flag];
0682         }
0683     }
0684 
0685     QCOMPARE(flagCounts["\\SEEN"], 2);
0686     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0687     QCOMPARE(flagCounts["$TODO"], 1);
0688     flagCounts.clear();
0689 
0690     // move from parent maildir to parent's sibling
0691     collection2.setParentCollection(target);
0692 
0693     job = mStore->moveCollection(collection1_1, collection2);
0694 
0695     QVERIFY(job->exec());
0696     QCOMPARE(job->error(), 0);
0697 
0698     QDir subDir2 = subDirTarget;
0699     QVERIFY(subDir2.cd(QStringLiteral(".collection2.directory")));
0700 
0701     collection = job->collection();
0702     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
0703     QCOMPARE(collection.parentCollection(), collection2);
0704 
0705     QFileInfo fileInfo1_1(subDir1, collection.remoteId());
0706     QVERIFY(!fileInfo1_1.exists());
0707     fileInfo1_1 = QFileInfo(subDir2, collection.remoteId());
0708     QVERIFY(fileInfo1_1.exists());
0709 
0710     // check for index preservation
0711     var = job->property("onDiskIndexInvalidated");
0712     QVERIFY(var.isValid());
0713     QCOMPARE(var.userType(), colListVar.userType());
0714 
0715     collections = var.value<Collection::List>();
0716     QCOMPARE((int)collections.count(), 1);
0717     QCOMPARE(collections.first(), collection);
0718 
0719     // get the items and check the flags (see data/README)
0720     itemFetch = mStore->fetchItems(collection);
0721     QVERIFY(itemFetch->exec());
0722     QCOMPARE(itemFetch->error(), 0);
0723 
0724     items = itemFetch->items();
0725     QCOMPARE((int)items.count(), 4);
0726     for (const Item &item : std::as_const(items)) {
0727         const auto flags = item.flags();
0728         for (const QByteArray &flag : flags) {
0729             ++flagCounts[flag];
0730         }
0731     }
0732 
0733     QCOMPARE(flagCounts["\\SEEN"], 2);
0734     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0735     QCOMPARE(flagCounts["$TODO"], 1);
0736     flagCounts.clear();
0737 
0738     // move from parent maildir to parent's sibling
0739     job = mStore->moveCollection(collection1_2, collection2);
0740 
0741     QVERIFY(job->exec());
0742     QCOMPARE(job->error(), 0);
0743 
0744     collection = job->collection();
0745     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
0746     QCOMPARE(collection.parentCollection(), collection2);
0747 
0748     QFileInfo fileInfo1_2(subDir1, collection.remoteId());
0749     QVERIFY(!fileInfo1_2.exists());
0750     fileInfo1_2 = QFileInfo(subDir2, collection.remoteId());
0751     QVERIFY(fileInfo1_2.exists());
0752 
0753     // check for index preservation
0754     var = job->property("onDiskIndexInvalidated");
0755     QVERIFY(var.isValid());
0756     QCOMPARE(var.userType(), colListVar.userType());
0757 
0758     collections = var.value<Collection::List>();
0759     QCOMPARE((int)collections.count(), 1);
0760     QCOMPARE(collections.first(), collection);
0761 
0762     // get the items and check the flags (see data/README)
0763     itemFetch = mStore->fetchItems(collection);
0764     QVERIFY(itemFetch->exec());
0765     QCOMPARE(itemFetch->error(), 0);
0766 
0767     items = itemFetch->items();
0768     QCOMPARE((int)items.count(), 4);
0769     for (const Item &item : std::as_const(items)) {
0770         const auto flags = item.flags();
0771         for (const QByteArray &flag : flags) {
0772             ++flagCounts[flag];
0773         }
0774     }
0775 
0776     QCOMPARE(flagCounts["\\SEEN"], 2);
0777     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0778     QCOMPARE(flagCounts["$TODO"], 1);
0779     flagCounts.clear();
0780 
0781     // move from parent mbox to parent's sibling
0782     job = mStore->moveCollection(collection4_1, collection2);
0783 
0784     QVERIFY(job->exec());
0785     QCOMPARE(job->error(), 0);
0786 
0787     collection = job->collection();
0788     QCOMPARE(collection.remoteId(), collection4_1.remoteId());
0789     QCOMPARE(collection.parentCollection(), collection2);
0790 
0791     QFileInfo fileInfo4_1(subDir4, collection.remoteId());
0792     QVERIFY(!fileInfo4_1.exists());
0793     fileInfo4_1 = QFileInfo(subDir2, collection.remoteId());
0794     QVERIFY(fileInfo4_1.exists());
0795 
0796     // check for index preservation
0797     var = job->property("onDiskIndexInvalidated");
0798     QVERIFY(var.isValid());
0799     QCOMPARE(var.userType(), colListVar.userType());
0800 
0801     collections = var.value<Collection::List>();
0802     QCOMPARE((int)collections.count(), 1);
0803     QCOMPARE(collections.first(), collection);
0804 
0805     // get the items and check the flags (see data/README)
0806     itemFetch = mStore->fetchItems(collection);
0807     QVERIFY(itemFetch->exec());
0808     QCOMPARE(itemFetch->error(), 0);
0809 
0810     items = itemFetch->items();
0811     QCOMPARE((int)items.count(), 4);
0812     for (const Item &item : std::as_const(items)) {
0813         const auto flags = item.flags();
0814         for (const QByteArray &flag : flags) {
0815             ++flagCounts[flag];
0816         }
0817     }
0818 
0819     QCOMPARE(flagCounts["\\SEEN"], 2);
0820     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0821     QCOMPARE(flagCounts["$TODO"], 1);
0822     flagCounts.clear();
0823 
0824     // move from parent mbox to parent's sibling
0825     job = mStore->moveCollection(collection4_2, collection2);
0826 
0827     QVERIFY(job->exec());
0828     QCOMPARE(job->error(), 0);
0829 
0830     collection = job->collection();
0831     QCOMPARE(collection.remoteId(), collection4_2.remoteId());
0832     QCOMPARE(collection.parentCollection(), collection2);
0833 
0834     QFileInfo fileInfo4_2(subDir4, collection.remoteId());
0835     QVERIFY(!fileInfo4_2.exists());
0836     fileInfo4_2 = QFileInfo(subDir2, collection.remoteId());
0837     QVERIFY(fileInfo4_2.exists());
0838 
0839     // check for index preservation
0840     var = job->property("onDiskIndexInvalidated");
0841     QVERIFY(var.isValid());
0842     QCOMPARE(var.userType(), colListVar.userType());
0843 
0844     collections = var.value<Collection::List>();
0845     QCOMPARE((int)collections.count(), 1);
0846     QCOMPARE(collections.first(), collection);
0847 
0848     // get the items and check the flags (see data/README)
0849     itemFetch = mStore->fetchItems(collection);
0850     QVERIFY(itemFetch->exec());
0851     QCOMPARE(itemFetch->error(), 0);
0852 
0853     items = itemFetch->items();
0854     QCOMPARE((int)items.count(), 4);
0855     for (const Item &item : std::as_const(items)) {
0856         const auto flags = item.flags();
0857         for (const QByteArray &flag : flags) {
0858             ++flagCounts[flag];
0859         }
0860     }
0861 
0862     QCOMPARE(flagCounts["\\SEEN"], 2);
0863     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0864     QCOMPARE(flagCounts["$TODO"], 1);
0865     flagCounts.clear();
0866 
0867     // move from parent maildir to grandparent
0868     collection1_1.setParentCollection(collection2);
0869 
0870     job = mStore->moveCollection(collection1_1, target);
0871 
0872     QVERIFY(job->exec());
0873     QCOMPARE(job->error(), 0);
0874 
0875     collection = job->collection();
0876     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
0877     QCOMPARE(collection.parentCollection(), target);
0878 
0879     fileInfo1_1.refresh();
0880     QVERIFY(!fileInfo1_1.exists());
0881     fileInfo1_1 = QFileInfo(subDirTarget, collection.remoteId());
0882     QVERIFY(fileInfo1_1.exists());
0883 
0884     // check for index preservation
0885     var = job->property("onDiskIndexInvalidated");
0886     QVERIFY(var.isValid());
0887     QCOMPARE(var.userType(), colListVar.userType());
0888 
0889     collections = var.value<Collection::List>();
0890     QCOMPARE((int)collections.count(), 1);
0891     QCOMPARE(collections.first(), collection);
0892 
0893     // get the items and check the flags (see data/README)
0894     itemFetch = mStore->fetchItems(collection);
0895     QVERIFY(itemFetch->exec());
0896     QCOMPARE(itemFetch->error(), 0);
0897 
0898     items = itemFetch->items();
0899     QCOMPARE((int)items.count(), 4);
0900     for (const Item &item : std::as_const(items)) {
0901         const auto flags{item.flags()};
0902         for (const QByteArray &flag : flags) {
0903             ++flagCounts[flag];
0904         }
0905     }
0906 
0907     QCOMPARE(flagCounts["\\SEEN"], 2);
0908     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0909     QCOMPARE(flagCounts["$TODO"], 1);
0910     flagCounts.clear();
0911 
0912     // move from parent maildir to grandparent
0913     collection1_2.setParentCollection(collection2);
0914     job = mStore->moveCollection(collection1_2, target);
0915 
0916     QVERIFY(job->exec());
0917     QCOMPARE(job->error(), 0);
0918 
0919     collection = job->collection();
0920     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
0921     QCOMPARE(collection.parentCollection(), target);
0922 
0923     fileInfo1_2.refresh();
0924     QVERIFY(!fileInfo1_2.exists());
0925     fileInfo1_2 = QFileInfo(subDirTarget, collection.remoteId());
0926     QVERIFY(fileInfo1_2.exists());
0927 
0928     // check for index preservation
0929     var = job->property("onDiskIndexInvalidated");
0930     QVERIFY(var.isValid());
0931     QCOMPARE(var.userType(), colListVar.userType());
0932 
0933     collections = var.value<Collection::List>();
0934     QCOMPARE((int)collections.count(), 1);
0935     QCOMPARE(collections.first(), collection);
0936 
0937     // get the items and check the flags (see data/README)
0938     itemFetch = mStore->fetchItems(collection);
0939     QVERIFY(itemFetch->exec());
0940     QCOMPARE(itemFetch->error(), 0);
0941 
0942     items = itemFetch->items();
0943     QCOMPARE((int)items.count(), 4);
0944     for (const Item &item : std::as_const(items)) {
0945         const auto flags{item.flags()};
0946         for (const QByteArray &flag : flags) {
0947             ++flagCounts[flag];
0948         }
0949     }
0950 
0951     QCOMPARE(flagCounts["\\SEEN"], 2);
0952     QCOMPARE(flagCounts["\\FLAGGED"], 1);
0953     QCOMPARE(flagCounts["$TODO"], 1);
0954     flagCounts.clear();
0955 
0956     // move from parent mbox to grandparent
0957     Collection collection4_3;
0958     collection4_3.setName(QStringLiteral("collection4_3"));
0959     collection4_3.setRemoteId(QStringLiteral("collection4_3"));
0960     collection4_3.setParentCollection(collection4);
0961 
0962     job = mStore->moveCollection(collection4_3, target);
0963 
0964     QVERIFY(job->exec());
0965     QCOMPARE(job->error(), 0);
0966 
0967     collection = job->collection();
0968     QCOMPARE(collection.remoteId(), collection4_3.remoteId());
0969     QCOMPARE(collection.parentCollection(), target);
0970 
0971     QFileInfo fileInfo4_3(subDir4, collection.remoteId());
0972     QVERIFY(!fileInfo4_3.exists());
0973     fileInfo4_3 = QFileInfo(subDirTarget, collection.remoteId());
0974     QVERIFY(fileInfo4_3.exists());
0975 
0976     // check for index preservation
0977     var = job->property("onDiskIndexInvalidated");
0978     QVERIFY(var.isValid());
0979     QCOMPARE(var.userType(), colListVar.userType());
0980 
0981     collections = var.value<Collection::List>();
0982     QCOMPARE((int)collections.count(), 1);
0983     QCOMPARE(collections.first(), collection);
0984 
0985     // get the items and check the flags (see data/README)
0986     itemFetch = mStore->fetchItems(collection);
0987     QVERIFY(itemFetch->exec());
0988     QCOMPARE(itemFetch->error(), 0);
0989 
0990     items = itemFetch->items();
0991     QCOMPARE((int)items.count(), 4);
0992     for (const Item &item : std::as_const(items)) {
0993         const auto flags{item.flags()};
0994         for (const QByteArray &flag : flags) {
0995             ++flagCounts[flag];
0996         }
0997     }
0998 
0999     QCOMPARE(flagCounts["\\SEEN"], 2);
1000     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1001     QCOMPARE(flagCounts["$TODO"], 1);
1002     flagCounts.clear();
1003 
1004     // move from parent mbox to grandparent
1005     Collection collection4_4;
1006     collection4_4.setName(QStringLiteral("collection4_4"));
1007     collection4_4.setRemoteId(QStringLiteral("collection4_4"));
1008     collection4_4.setParentCollection(collection4);
1009 
1010     job = mStore->moveCollection(collection4_4, target);
1011 
1012     QVERIFY(job->exec());
1013     QCOMPARE(job->error(), 0);
1014 
1015     collection = job->collection();
1016     QCOMPARE(collection.remoteId(), collection4_4.remoteId());
1017     QCOMPARE(collection.parentCollection(), target);
1018 
1019     QFileInfo fileInfo4_4(subDir4, collection.remoteId());
1020     QVERIFY(!fileInfo4_4.exists());
1021     fileInfo4_4 = QFileInfo(subDirTarget, collection.remoteId());
1022     QVERIFY(fileInfo4_4.exists());
1023 
1024     // check for index preservation
1025     var = job->property("onDiskIndexInvalidated");
1026     QVERIFY(var.isValid());
1027     QCOMPARE(var.userType(), colListVar.userType());
1028 
1029     collections = var.value<Collection::List>();
1030     QCOMPARE((int)collections.count(), 1);
1031     QCOMPARE(collections.first(), collection);
1032 
1033     // get the items and check the flags (see data/README)
1034     itemFetch = mStore->fetchItems(collection);
1035     QVERIFY(itemFetch->exec());
1036     QCOMPARE(itemFetch->error(), 0);
1037 
1038     items = itemFetch->items();
1039     QCOMPARE((int)items.count(), 4);
1040     for (const Item &item : std::as_const(items)) {
1041         const auto flags{item.flags()};
1042         for (const QByteArray &flag : flags) {
1043             ++flagCounts[flag];
1044         }
1045     }
1046 
1047     QCOMPARE(flagCounts["\\SEEN"], 2);
1048     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1049     QCOMPARE(flagCounts["$TODO"], 1);
1050     flagCounts.clear();
1051 
1052     // move from maildir to grandchild
1053     collection1_1.setParentCollection(target);
1054 
1055     job = mStore->moveCollection(collection1_1, collection2);
1056 
1057     QVERIFY(job->exec());
1058     QCOMPARE(job->error(), 0);
1059 
1060     collection = job->collection();
1061     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
1062     QCOMPARE(collection.parentCollection(), collection2);
1063 
1064     fileInfo1_1.refresh();
1065     QVERIFY(!fileInfo1_1.exists());
1066     fileInfo1_1 = QFileInfo(subDir2, collection.remoteId());
1067     QVERIFY(fileInfo1_1.exists());
1068 
1069     // check for index preservation
1070     var = job->property("onDiskIndexInvalidated");
1071     QVERIFY(var.isValid());
1072     QCOMPARE(var.userType(), colListVar.userType());
1073 
1074     collections = var.value<Collection::List>();
1075     QCOMPARE((int)collections.count(), 1);
1076     QCOMPARE(collections.first(), collection);
1077 
1078     // get the items and check the flags (see data/README)
1079     itemFetch = mStore->fetchItems(collection);
1080     QVERIFY(itemFetch->exec());
1081     QCOMPARE(itemFetch->error(), 0);
1082 
1083     items = itemFetch->items();
1084     QCOMPARE((int)items.count(), 4);
1085     for (const Item &item : std::as_const(items)) {
1086         const auto flags{item.flags()};
1087         for (const QByteArray &flag : flags) {
1088             ++flagCounts[flag];
1089         }
1090     }
1091 
1092     QCOMPARE(flagCounts["\\SEEN"], 2);
1093     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1094     QCOMPARE(flagCounts["$TODO"], 1);
1095     flagCounts.clear();
1096 
1097     // move from maildir to grandchild
1098     collection1_2.setParentCollection(target);
1099 
1100     job = mStore->moveCollection(collection1_2, collection2);
1101 
1102     QVERIFY(job->exec());
1103     QCOMPARE(job->error(), 0);
1104 
1105     collection = job->collection();
1106     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
1107     QCOMPARE(collection.parentCollection(), collection2);
1108 
1109     fileInfo1_2.refresh();
1110     QVERIFY(!fileInfo1_2.exists());
1111     fileInfo1_2 = QFileInfo(subDir2, collection.remoteId());
1112     QVERIFY(fileInfo1_2.exists());
1113 
1114     // check for index preservation
1115     var = job->property("onDiskIndexInvalidated");
1116     QVERIFY(var.isValid());
1117     QCOMPARE(var.userType(), colListVar.userType());
1118 
1119     collections = var.value<Collection::List>();
1120     QCOMPARE((int)collections.count(), 1);
1121     QCOMPARE(collections.first(), collection);
1122 
1123     // get the items and check the flags (see data/README)
1124     itemFetch = mStore->fetchItems(collection);
1125     QVERIFY(itemFetch->exec());
1126     QCOMPARE(itemFetch->error(), 0);
1127 
1128     items = itemFetch->items();
1129     QCOMPARE((int)items.count(), 4);
1130     for (const Item &item : std::as_const(items)) {
1131         const auto flags{item.flags()};
1132         for (const QByteArray &flag : flags) {
1133             ++flagCounts[flag];
1134         }
1135     }
1136 
1137     QCOMPARE(flagCounts["\\SEEN"], 2);
1138     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1139     QCOMPARE(flagCounts["$TODO"], 1);
1140     flagCounts.clear();
1141 }
1142 
1143 void CollectionMoveTest::testMoveToMBox()
1144 {
1145     QDir topDir(mDir->path());
1146 
1147     // top level dir
1148     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), topDir.path(), QStringLiteral("collection1")));
1149     QFileInfo fileInfo1(topDir, QStringLiteral("collection1"));
1150     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), topDir.path(), QStringLiteral("collection2")));
1151     QFileInfo fileInfo2(topDir, QStringLiteral("collection2"));
1152     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection3")));
1153     QFileInfo fileInfo3(topDir, QStringLiteral("collection3"));
1154     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection4")));
1155     QFileInfo fileInfo4(topDir, QStringLiteral("collection4"));
1156     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection5")));
1157     QFileInfo fileInfo5(topDir, QStringLiteral("collection5"));
1158     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), topDir.path(), QStringLiteral("collection6")));
1159 
1160     // first level maildir parent
1161     QDir subDir1 = topDir;
1162     QVERIFY(subDir1.mkdir(QStringLiteral(".collection1.directory")));
1163     QVERIFY(subDir1.cd(QStringLiteral(".collection1.directory")));
1164     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir1.path(), QStringLiteral("collection1_1")));
1165     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir1.path(), QStringLiteral("collection1_2")));
1166     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir1.path(), QStringLiteral("collection1_3")));
1167     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir1.path(), QStringLiteral("collection1_4")));
1168 
1169     // first level mbox parent
1170     QDir subDir4 = topDir;
1171     QVERIFY(subDir4.mkdir(QStringLiteral(".collection4.directory")));
1172     QVERIFY(subDir4.cd(QStringLiteral(".collection4.directory")));
1173     QVERIFY(TestDataUtil::installFolder(QStringLiteral("mbox"), subDir4.path(), QStringLiteral("collection4_1")));
1174     QVERIFY(TestDataUtil::installFolder(QStringLiteral("maildir"), subDir4.path(), QStringLiteral("collection4_2")));
1175 
1176     // target mbox
1177     QFileInfo fileInfoTarget(topDir.path(), QStringLiteral("target"));
1178     QFile fileTarget(fileInfoTarget.absoluteFilePath());
1179     QVERIFY(fileTarget.open(QIODevice::WriteOnly));
1180     fileTarget.close();
1181     QVERIFY(fileInfoTarget.exists());
1182 
1183     QDir subDirTarget;
1184 
1185     mStore->setPath(topDir.path());
1186 
1187     // common variables
1188     FileStore::CollectionMoveJob *job = nullptr;
1189     FileStore::ItemFetchJob *itemFetch = nullptr;
1190     Collection collection;
1191     const QVariant colListVar = QVariant::fromValue<Collection::List>(Collection::List());
1192     QVariant var;
1193     Collection::List collections;
1194     Item::List items;
1195     QMap<QByteArray, int> flagCounts;
1196 
1197     Collection target;
1198     target.setName(QStringLiteral("target"));
1199     target.setRemoteId(QStringLiteral("target"));
1200     target.setParentCollection(mStore->topLevelCollection());
1201 
1202     // test move leaf maildir into sibling
1203     Collection collection2;
1204     collection2.setName(QStringLiteral("collection2"));
1205     collection2.setRemoteId(QStringLiteral("collection2"));
1206     collection2.setParentCollection(mStore->topLevelCollection());
1207 
1208     job = mStore->moveCollection(collection2, target);
1209 
1210     QVERIFY(job->exec());
1211     QCOMPARE(job->error(), 0);
1212 
1213     subDirTarget = topDir;
1214     QVERIFY(subDirTarget.cd(QStringLiteral(".target.directory")));
1215 
1216     collection = job->collection();
1217     QCOMPARE(collection.remoteId(), collection2.remoteId());
1218     QCOMPARE(collection.parentCollection(), target);
1219 
1220     fileInfo2.refresh();
1221     QVERIFY(!fileInfo2.exists());
1222     fileInfo2 = QFileInfo(subDirTarget, collection.remoteId());
1223     QVERIFY(fileInfo2.exists());
1224 
1225     // check for index preservation
1226     var = job->property("onDiskIndexInvalidated");
1227     QVERIFY(var.isValid());
1228     QCOMPARE(var.userType(), colListVar.userType());
1229 
1230     collections = var.value<Collection::List>();
1231     QCOMPARE((int)collections.count(), 1);
1232     QCOMPARE(collections.first(), collection);
1233 
1234     // get the items and check the flags (see data/README)
1235     itemFetch = mStore->fetchItems(collection);
1236     QVERIFY(itemFetch->exec());
1237     QCOMPARE(itemFetch->error(), 0);
1238 
1239     items = itemFetch->items();
1240     QCOMPARE((int)items.count(), 4);
1241     for (const Item &item : std::as_const(items)) {
1242         const auto flags{item.flags()};
1243         for (const QByteArray &flag : flags) {
1244             ++flagCounts[flag];
1245         }
1246     }
1247 
1248     QCOMPARE(flagCounts["\\SEEN"], 2);
1249     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1250     QCOMPARE(flagCounts["$TODO"], 1);
1251     flagCounts.clear();
1252 
1253     // test move leaf mbox into sibling
1254     Collection collection3;
1255     collection3.setName(QStringLiteral("collection3"));
1256     collection3.setRemoteId(QStringLiteral("collection3"));
1257     collection3.setParentCollection(mStore->topLevelCollection());
1258 
1259     job = mStore->moveCollection(collection3, target);
1260 
1261     QVERIFY(job->exec());
1262     QCOMPARE(job->error(), 0);
1263 
1264     collection = job->collection();
1265     QCOMPARE(collection.remoteId(), collection3.remoteId());
1266     QCOMPARE(collection.parentCollection(), target);
1267 
1268     fileInfo3.refresh();
1269     QVERIFY(!fileInfo3.exists());
1270     fileInfo3 = QFileInfo(subDirTarget, collection.remoteId());
1271     QVERIFY(fileInfo3.exists());
1272 
1273     // check for index preservation
1274     var = job->property("onDiskIndexInvalidated");
1275     QVERIFY(var.isValid());
1276     QCOMPARE(var.userType(), colListVar.userType());
1277 
1278     collections = var.value<Collection::List>();
1279     QCOMPARE((int)collections.count(), 1);
1280     QCOMPARE(collections.first(), collection);
1281 
1282     // get the items and check the flags (see data/README)
1283     itemFetch = mStore->fetchItems(collection);
1284     QVERIFY(itemFetch->exec());
1285     QCOMPARE(itemFetch->error(), 0);
1286 
1287     items = itemFetch->items();
1288     QCOMPARE((int)items.count(), 4);
1289     for (const Item &item : std::as_const(items)) {
1290         const auto flags{item.flags()};
1291         for (const QByteArray &flag : flags) {
1292             ++flagCounts[flag];
1293         }
1294     }
1295 
1296     QCOMPARE(flagCounts["\\SEEN"], 2);
1297     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1298     QCOMPARE(flagCounts["$TODO"], 1);
1299     flagCounts.clear();
1300 
1301     // test move leaf mbox into sibling without subtree
1302     Collection collection5;
1303     collection5.setName(QStringLiteral("collection5"));
1304     collection5.setRemoteId(QStringLiteral("collection5"));
1305     collection5.setParentCollection(mStore->topLevelCollection());
1306 
1307     Collection collection6;
1308     collection6.setName(QStringLiteral("collection6"));
1309     collection6.setRemoteId(QStringLiteral("collection6"));
1310     collection6.setParentCollection(mStore->topLevelCollection());
1311 
1312     job = mStore->moveCollection(collection5, collection6);
1313 
1314     QVERIFY(job->exec());
1315     QCOMPARE(job->error(), 0);
1316 
1317     collection = job->collection();
1318     QCOMPARE(collection.remoteId(), collection5.remoteId());
1319     QCOMPARE(collection.parentCollection(), collection6);
1320 
1321     fileInfo5.refresh();
1322     QVERIFY(!fileInfo5.exists());
1323     QDir subDir6 = topDir;
1324     QVERIFY(subDir6.cd(QStringLiteral(".collection6.directory")));
1325     fileInfo5 = QFileInfo(subDir6, collection.remoteId());
1326     QVERIFY(fileInfo5.exists());
1327 
1328     // check for index preservation
1329     var = job->property("onDiskIndexInvalidated");
1330     QVERIFY(var.isValid());
1331     QCOMPARE(var.userType(), colListVar.userType());
1332 
1333     collections = var.value<Collection::List>();
1334     QCOMPARE((int)collections.count(), 1);
1335     QCOMPARE(collections.first(), collection);
1336 
1337     // get the items and check the flags (see data/README)
1338     itemFetch = mStore->fetchItems(collection);
1339     QVERIFY(itemFetch->exec());
1340     QCOMPARE(itemFetch->error(), 0);
1341 
1342     items = itemFetch->items();
1343     QCOMPARE((int)items.count(), 4);
1344     for (const Item &item : std::as_const(items)) {
1345         const auto flags{item.flags()};
1346         for (const QByteArray &flag : flags) {
1347             ++flagCounts[flag];
1348         }
1349     }
1350 
1351     QCOMPARE(flagCounts["\\SEEN"], 2);
1352     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1353     QCOMPARE(flagCounts["$TODO"], 1);
1354     flagCounts.clear();
1355 
1356     // test move maildir with subtree into sibling
1357     Collection collection1;
1358     collection1.setName(QStringLiteral("collection1"));
1359     collection1.setRemoteId(QStringLiteral("collection1"));
1360     collection1.setParentCollection(mStore->topLevelCollection());
1361 
1362     // load sub collection index data to check for correct cache updates
1363     Collection collection1_1;
1364     collection1_1.setName(QStringLiteral("collection1_1"));
1365     collection1_1.setRemoteId(QStringLiteral("collection1_1"));
1366     collection1_1.setParentCollection(collection1);
1367     itemFetch = mStore->fetchItems(collection1_1);
1368     QVERIFY(itemFetch->exec());
1369 
1370     Collection collection1_2;
1371     collection1_2.setName(QStringLiteral("collection1_2"));
1372     collection1_2.setRemoteId(QStringLiteral("collection1_2"));
1373     collection1_2.setParentCollection(collection1);
1374     itemFetch = mStore->fetchItems(collection1_2);
1375     QVERIFY(itemFetch->exec());
1376 
1377     job = mStore->moveCollection(collection1, target);
1378 
1379     QVERIFY(job->exec());
1380     QCOMPARE(job->error(), 0);
1381 
1382     collection = job->collection();
1383     QCOMPARE(collection.remoteId(), collection1.remoteId());
1384     QCOMPARE(collection.parentCollection(), target);
1385 
1386     fileInfo1.refresh();
1387     QVERIFY(!fileInfo1.exists());
1388     fileInfo1 = QFileInfo(subDirTarget, collection.remoteId());
1389     QVERIFY(fileInfo1.exists());
1390     QVERIFY(!subDir1.exists());
1391     subDir1 = subDirTarget;
1392     QVERIFY(subDir1.cd(QStringLiteral(".collection1.directory")));
1393     QCOMPARE(subDir1.entryList(QStringList() << QStringLiteral("collection*")),
1394              QStringList() << QStringLiteral("collection1_1") << QStringLiteral("collection1_2") << QStringLiteral("collection1_3")
1395                            << QStringLiteral("collection1_4"));
1396 
1397     // check for index preservation
1398     var = job->property("onDiskIndexInvalidated");
1399     QVERIFY(var.isValid());
1400     QCOMPARE(var.userType(), colListVar.userType());
1401 
1402     collections = var.value<Collection::List>();
1403     QCOMPARE((int)collections.count(), 1);
1404     QCOMPARE(collections.first(), collection);
1405 
1406     // get the items and check the flags (see data/README)
1407     itemFetch = mStore->fetchItems(collection);
1408     QVERIFY(itemFetch->exec());
1409     QCOMPARE(itemFetch->error(), 0);
1410 
1411     items = itemFetch->items();
1412     QCOMPARE((int)items.count(), 4);
1413     for (const Item &item : std::as_const(items)) {
1414         const auto flags{item.flags()};
1415         for (const QByteArray &flag : flags) {
1416             ++flagCounts[flag];
1417         }
1418     }
1419 
1420     QCOMPARE(flagCounts["\\SEEN"], 2);
1421     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1422     QCOMPARE(flagCounts["$TODO"], 1);
1423     flagCounts.clear();
1424 
1425     // check for children cache path updates
1426     collection1.setParentCollection(target);
1427     collection1_1.setParentCollection(collection1);
1428     collection1_2.setParentCollection(collection1);
1429 
1430     itemFetch = mStore->fetchItems(collection1_1);
1431     QVERIFY(itemFetch->exec());
1432     QCOMPARE(itemFetch->error(), 0);
1433 
1434     items = itemFetch->items();
1435     QCOMPARE((int)items.count(), 4);
1436     for (const Item &item : std::as_const(items)) {
1437         const auto flags{item.flags()};
1438         for (const QByteArray &flag : flags) {
1439             ++flagCounts[flag];
1440         }
1441     }
1442 
1443     QCOMPARE(flagCounts["\\SEEN"], 2);
1444     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1445     QCOMPARE(flagCounts["$TODO"], 1);
1446     flagCounts.clear();
1447 
1448     itemFetch = mStore->fetchItems(collection1_2);
1449     QVERIFY(itemFetch->exec());
1450     QCOMPARE(itemFetch->error(), 0);
1451 
1452     items = itemFetch->items();
1453     QCOMPARE((int)items.count(), 4);
1454     for (const Item &item : std::as_const(items)) {
1455         const auto flags{item.flags()};
1456         for (const QByteArray &flag : flags) {
1457             ++flagCounts[flag];
1458         }
1459     }
1460 
1461     QCOMPARE(flagCounts["\\SEEN"], 2);
1462     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1463     QCOMPARE(flagCounts["$TODO"], 1);
1464     flagCounts.clear();
1465 
1466     // test move mbox with subtree into sibling
1467     Collection collection4;
1468     collection4.setName(QStringLiteral("collection4"));
1469     collection4.setRemoteId(QStringLiteral("collection4"));
1470     collection4.setParentCollection(mStore->topLevelCollection());
1471 
1472     // load sub collection index data to check for correct cache updates
1473     Collection collection4_1;
1474     collection4_1.setName(QStringLiteral("collection4_1"));
1475     collection4_1.setRemoteId(QStringLiteral("collection4_1"));
1476     collection4_1.setParentCollection(collection4);
1477     itemFetch = mStore->fetchItems(collection4_1);
1478     QVERIFY(itemFetch->exec());
1479 
1480     Collection collection4_2;
1481     collection4_2.setName(QStringLiteral("collection4_2"));
1482     collection4_2.setRemoteId(QStringLiteral("collection4_2"));
1483     collection4_2.setParentCollection(collection4);
1484     itemFetch = mStore->fetchItems(collection4_2);
1485     QVERIFY(itemFetch->exec());
1486 
1487     job = mStore->moveCollection(collection4, target);
1488 
1489     QVERIFY(job->exec());
1490     QCOMPARE(job->error(), 0);
1491 
1492     collection = job->collection();
1493     QCOMPARE(collection.remoteId(), collection4.remoteId());
1494     QCOMPARE(collection.parentCollection(), target);
1495 
1496     fileInfo4.refresh();
1497     QVERIFY(!fileInfo4.exists());
1498     fileInfo4 = QFileInfo(subDirTarget, collection.remoteId());
1499     QVERIFY(fileInfo4.exists());
1500     QVERIFY(!subDir4.exists());
1501     subDir4 = subDirTarget;
1502     QVERIFY(subDir4.cd(QStringLiteral(".collection4.directory")));
1503     QCOMPARE(subDir4.entryList(QStringList() << QStringLiteral("collection*")),
1504              QStringList() << QStringLiteral("collection4_1") << QStringLiteral("collection4_2"));
1505 
1506     // check for index preservation
1507     var = job->property("onDiskIndexInvalidated");
1508     QVERIFY(var.isValid());
1509     QCOMPARE(var.userType(), colListVar.userType());
1510 
1511     collections = var.value<Collection::List>();
1512     QCOMPARE((int)collections.count(), 1);
1513     QCOMPARE(collections.first(), collection);
1514 
1515     // get the items and check the flags (see data/README)
1516     itemFetch = mStore->fetchItems(collection);
1517     QVERIFY(itemFetch->exec());
1518     QCOMPARE(itemFetch->error(), 0);
1519 
1520     items = itemFetch->items();
1521     QCOMPARE((int)items.count(), 4);
1522     for (const Item &item : std::as_const(items)) {
1523         const auto flags{item.flags()};
1524         for (const QByteArray &flag : flags) {
1525             ++flagCounts[flag];
1526         }
1527     }
1528 
1529     QCOMPARE(flagCounts["\\SEEN"], 2);
1530     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1531     QCOMPARE(flagCounts["$TODO"], 1);
1532     flagCounts.clear();
1533 
1534     // check for children cache path updates
1535     collection4.setParentCollection(target);
1536     collection4_1.setParentCollection(collection4);
1537     collection4_2.setParentCollection(collection4);
1538 
1539     itemFetch = mStore->fetchItems(collection4_1);
1540     QVERIFY(itemFetch->exec());
1541     QCOMPARE(itemFetch->error(), 0);
1542 
1543     items = itemFetch->items();
1544     QCOMPARE((int)items.count(), 4);
1545     for (const Item &item : std::as_const(items)) {
1546         const auto flags{item.flags()};
1547         for (const QByteArray &flag : flags) {
1548             ++flagCounts[flag];
1549         }
1550     }
1551 
1552     QCOMPARE(flagCounts["\\SEEN"], 2);
1553     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1554     QCOMPARE(flagCounts["$TODO"], 1);
1555     flagCounts.clear();
1556 
1557     itemFetch = mStore->fetchItems(collection4_2);
1558     QVERIFY(itemFetch->exec());
1559     QCOMPARE(itemFetch->error(), 0);
1560 
1561     items = itemFetch->items();
1562     QCOMPARE((int)items.count(), 4);
1563     for (const Item &item : std::as_const(items)) {
1564         const auto flags{item.flags()};
1565         for (const QByteArray &flag : flags) {
1566             ++flagCounts[flag];
1567         }
1568     }
1569 
1570     QCOMPARE(flagCounts["\\SEEN"], 2);
1571     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1572     QCOMPARE(flagCounts["$TODO"], 1);
1573     flagCounts.clear();
1574 
1575     // move from parent maildir to parent's sibling
1576     collection3.setParentCollection(target);
1577 
1578     job = mStore->moveCollection(collection1_1, collection3);
1579 
1580     QVERIFY(job->exec());
1581     QCOMPARE(job->error(), 0);
1582 
1583     QDir subDir3 = subDirTarget;
1584     QVERIFY(subDir3.cd(QStringLiteral(".collection3.directory")));
1585 
1586     collection = job->collection();
1587     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
1588     QCOMPARE(collection.parentCollection(), collection3);
1589 
1590     QFileInfo fileInfo1_1(subDir1, collection.remoteId());
1591     QVERIFY(!fileInfo1_1.exists());
1592     fileInfo1_1 = QFileInfo(subDir3, collection.remoteId());
1593     QVERIFY(fileInfo1_1.exists());
1594 
1595     // check for index preservation
1596     var = job->property("onDiskIndexInvalidated");
1597     QVERIFY(var.isValid());
1598     QCOMPARE(var.userType(), colListVar.userType());
1599 
1600     collections = var.value<Collection::List>();
1601     QCOMPARE((int)collections.count(), 1);
1602     QCOMPARE(collections.first(), collection);
1603 
1604     // get the items and check the flags (see data/README)
1605     itemFetch = mStore->fetchItems(collection);
1606     QVERIFY(itemFetch->exec());
1607     QCOMPARE(itemFetch->error(), 0);
1608 
1609     items = itemFetch->items();
1610     QCOMPARE((int)items.count(), 4);
1611     for (const Item &item : std::as_const(items)) {
1612         const auto flags{item.flags()};
1613         for (const QByteArray &flag : flags) {
1614             ++flagCounts[flag];
1615         }
1616     }
1617 
1618     QCOMPARE(flagCounts["\\SEEN"], 2);
1619     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1620     QCOMPARE(flagCounts["$TODO"], 1);
1621     flagCounts.clear();
1622 
1623     // move from parent maildir to parent's sibling
1624     job = mStore->moveCollection(collection1_2, collection3);
1625 
1626     QVERIFY(job->exec());
1627     QCOMPARE(job->error(), 0);
1628 
1629     collection = job->collection();
1630     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
1631     QCOMPARE(collection.parentCollection(), collection3);
1632 
1633     QFileInfo fileInfo1_2(subDir1, collection.remoteId());
1634     QVERIFY(!fileInfo1_2.exists());
1635     fileInfo1_2 = QFileInfo(subDir3, collection.remoteId());
1636     QVERIFY(fileInfo1_2.exists());
1637 
1638     // check for index preservation
1639     var = job->property("onDiskIndexInvalidated");
1640     QVERIFY(var.isValid());
1641     QCOMPARE(var.userType(), colListVar.userType());
1642 
1643     collections = var.value<Collection::List>();
1644     QCOMPARE((int)collections.count(), 1);
1645     QCOMPARE(collections.first(), collection);
1646 
1647     // get the items and check the flags (see data/README)
1648     itemFetch = mStore->fetchItems(collection);
1649     QVERIFY(itemFetch->exec());
1650     QCOMPARE(itemFetch->error(), 0);
1651 
1652     items = itemFetch->items();
1653     QCOMPARE((int)items.count(), 4);
1654     for (const Item &item : std::as_const(items)) {
1655         const auto flags{item.flags()};
1656         for (const QByteArray &flag : flags) {
1657             ++flagCounts[flag];
1658         }
1659     }
1660 
1661     QCOMPARE(flagCounts["\\SEEN"], 2);
1662     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1663     QCOMPARE(flagCounts["$TODO"], 1);
1664     flagCounts.clear();
1665 
1666     // move from parent mbox to parent's sibling
1667     job = mStore->moveCollection(collection4_1, collection3);
1668 
1669     QVERIFY(job->exec());
1670     QCOMPARE(job->error(), 0);
1671 
1672     collection = job->collection();
1673     QCOMPARE(collection.remoteId(), collection4_1.remoteId());
1674     QCOMPARE(collection.parentCollection(), collection3);
1675 
1676     QFileInfo fileInfo4_1(subDir4, collection.remoteId());
1677     QVERIFY(!fileInfo4_1.exists());
1678     fileInfo4_1 = QFileInfo(subDir3, collection.remoteId());
1679     QVERIFY(fileInfo4_1.exists());
1680 
1681     // check for index preservation
1682     var = job->property("onDiskIndexInvalidated");
1683     QVERIFY(var.isValid());
1684     QCOMPARE(var.userType(), colListVar.userType());
1685 
1686     collections = var.value<Collection::List>();
1687     QCOMPARE((int)collections.count(), 1);
1688     QCOMPARE(collections.first(), collection);
1689 
1690     // get the items and check the flags (see data/README)
1691     itemFetch = mStore->fetchItems(collection);
1692     QVERIFY(itemFetch->exec());
1693     QCOMPARE(itemFetch->error(), 0);
1694 
1695     items = itemFetch->items();
1696     QCOMPARE((int)items.count(), 4);
1697     for (const Item &item : std::as_const(items)) {
1698         const auto flags{item.flags()};
1699         for (const QByteArray &flag : flags) {
1700             ++flagCounts[flag];
1701         }
1702     }
1703 
1704     QCOMPARE(flagCounts["\\SEEN"], 2);
1705     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1706     QCOMPARE(flagCounts["$TODO"], 1);
1707     flagCounts.clear();
1708 
1709     // move from parent mbox to parent's sibling
1710     job = mStore->moveCollection(collection4_2, collection3);
1711 
1712     QVERIFY(job->exec());
1713     QCOMPARE(job->error(), 0);
1714 
1715     collection = job->collection();
1716     QCOMPARE(collection.remoteId(), collection4_2.remoteId());
1717     QCOMPARE(collection.parentCollection(), collection3);
1718 
1719     QFileInfo fileInfo4_2(subDir4, collection.remoteId());
1720     QVERIFY(!fileInfo4_2.exists());
1721     fileInfo4_2 = QFileInfo(subDir3, collection.remoteId());
1722     QVERIFY(fileInfo4_2.exists());
1723 
1724     // check for index preservation
1725     var = job->property("onDiskIndexInvalidated");
1726     QVERIFY(var.isValid());
1727     QCOMPARE(var.userType(), colListVar.userType());
1728 
1729     collections = var.value<Collection::List>();
1730     QCOMPARE((int)collections.count(), 1);
1731     QCOMPARE(collections.first(), collection);
1732 
1733     // get the items and check the flags (see data/README)
1734     itemFetch = mStore->fetchItems(collection);
1735     QVERIFY(itemFetch->exec());
1736     QCOMPARE(itemFetch->error(), 0);
1737 
1738     items = itemFetch->items();
1739     QCOMPARE((int)items.count(), 4);
1740     for (const Item &item : std::as_const(items)) {
1741         const auto flags{item.flags()};
1742         for (const QByteArray &flag : flags) {
1743             ++flagCounts[flag];
1744         }
1745     }
1746 
1747     QCOMPARE(flagCounts["\\SEEN"], 2);
1748     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1749     QCOMPARE(flagCounts["$TODO"], 1);
1750     flagCounts.clear();
1751 
1752     // move from parent mbox to grandparent
1753     collection1_1.setParentCollection(collection3);
1754 
1755     job = mStore->moveCollection(collection1_1, target);
1756 
1757     QVERIFY(job->exec());
1758     QCOMPARE(job->error(), 0);
1759 
1760     collection = job->collection();
1761     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
1762     QCOMPARE(collection.parentCollection(), target);
1763 
1764     fileInfo1_1.refresh();
1765     QVERIFY(!fileInfo1_1.exists());
1766     fileInfo1_1 = QFileInfo(subDirTarget, collection.remoteId());
1767     QVERIFY(fileInfo1_1.exists());
1768 
1769     // check for index preservation
1770     var = job->property("onDiskIndexInvalidated");
1771     QVERIFY(var.isValid());
1772     QCOMPARE(var.userType(), colListVar.userType());
1773 
1774     collections = var.value<Collection::List>();
1775     QCOMPARE((int)collections.count(), 1);
1776     QCOMPARE(collections.first(), collection);
1777 
1778     // get the items and check the flags (see data/README)
1779     itemFetch = mStore->fetchItems(collection);
1780     QVERIFY(itemFetch->exec());
1781     QCOMPARE(itemFetch->error(), 0);
1782 
1783     items = itemFetch->items();
1784     QCOMPARE((int)items.count(), 4);
1785     for (const Item &item : std::as_const(items)) {
1786         const auto flags{item.flags()};
1787         for (const QByteArray &flag : flags) {
1788             ++flagCounts[flag];
1789         }
1790     }
1791 
1792     QCOMPARE(flagCounts["\\SEEN"], 2);
1793     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1794     QCOMPARE(flagCounts["$TODO"], 1);
1795     flagCounts.clear();
1796 
1797     // move from parent mbox to grandparent
1798     collection1_2.setParentCollection(collection3);
1799     job = mStore->moveCollection(collection1_2, target);
1800 
1801     QVERIFY(job->exec());
1802     QCOMPARE(job->error(), 0);
1803 
1804     collection = job->collection();
1805     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
1806     QCOMPARE(collection.parentCollection(), target);
1807 
1808     fileInfo1_2.refresh();
1809     QVERIFY(!fileInfo1_2.exists());
1810     fileInfo1_2 = QFileInfo(subDirTarget, collection.remoteId());
1811     QVERIFY(fileInfo1_2.exists());
1812 
1813     // check for index preservation
1814     var = job->property("onDiskIndexInvalidated");
1815     QVERIFY(var.isValid());
1816     QCOMPARE(var.userType(), colListVar.userType());
1817 
1818     collections = var.value<Collection::List>();
1819     QCOMPARE((int)collections.count(), 1);
1820     QCOMPARE(collections.first(), collection);
1821 
1822     // get the items and check the flags (see data/README)
1823     itemFetch = mStore->fetchItems(collection);
1824     QVERIFY(itemFetch->exec());
1825     QCOMPARE(itemFetch->error(), 0);
1826 
1827     items = itemFetch->items();
1828     QCOMPARE((int)items.count(), 4);
1829     for (const Item &item : std::as_const(items)) {
1830         const auto flags{item.flags()};
1831         for (const QByteArray &flag : flags) {
1832             ++flagCounts[flag];
1833         }
1834     }
1835 
1836     QCOMPARE(flagCounts["\\SEEN"], 2);
1837     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1838     QCOMPARE(flagCounts["$TODO"], 1);
1839     flagCounts.clear();
1840 
1841     // move from parent maildir to grandparent
1842     Collection collection1_3;
1843     collection1_3.setName(QStringLiteral("collection1_3"));
1844     collection1_3.setRemoteId(QStringLiteral("collection1_3"));
1845     collection1_3.setParentCollection(collection1);
1846 
1847     job = mStore->moveCollection(collection1_3, target);
1848 
1849     QVERIFY(job->exec());
1850     QCOMPARE(job->error(), 0);
1851 
1852     collection = job->collection();
1853     QCOMPARE(collection.remoteId(), collection1_3.remoteId());
1854     QCOMPARE(collection.parentCollection(), target);
1855 
1856     QFileInfo fileInfo1_3(subDir1, collection.remoteId());
1857     QVERIFY(!fileInfo1_3.exists());
1858     fileInfo1_3 = QFileInfo(subDirTarget, collection.remoteId());
1859     QVERIFY(fileInfo1_3.exists());
1860 
1861     // check for index preservation
1862     var = job->property("onDiskIndexInvalidated");
1863     QVERIFY(var.isValid());
1864     QCOMPARE(var.userType(), colListVar.userType());
1865 
1866     collections = var.value<Collection::List>();
1867     QCOMPARE((int)collections.count(), 1);
1868     QCOMPARE(collections.first(), collection);
1869 
1870     // get the items and check the flags (see data/README)
1871     itemFetch = mStore->fetchItems(collection);
1872     QVERIFY(itemFetch->exec());
1873     QCOMPARE(itemFetch->error(), 0);
1874 
1875     items = itemFetch->items();
1876     QCOMPARE((int)items.count(), 4);
1877     for (const Item &item : std::as_const(items)) {
1878         const auto flags{item.flags()};
1879         for (const QByteArray &flag : flags) {
1880             ++flagCounts[flag];
1881         }
1882     }
1883 
1884     QCOMPARE(flagCounts["\\SEEN"], 2);
1885     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1886     QCOMPARE(flagCounts["$TODO"], 1);
1887     flagCounts.clear();
1888 
1889     // move from parent maildir to grandparent
1890     Collection collection1_4;
1891     collection1_4.setName(QStringLiteral("collection1_4"));
1892     collection1_4.setRemoteId(QStringLiteral("collection1_4"));
1893     collection1_4.setParentCollection(collection1);
1894 
1895     job = mStore->moveCollection(collection1_4, target);
1896 
1897     QVERIFY(job->exec());
1898     QCOMPARE(job->error(), 0);
1899 
1900     collection = job->collection();
1901     QCOMPARE(collection.remoteId(), collection1_4.remoteId());
1902     QCOMPARE(collection.parentCollection(), target);
1903 
1904     QFileInfo fileInfo1_4(subDir1, collection.remoteId());
1905     QVERIFY(!fileInfo1_4.exists());
1906     fileInfo1_4 = QFileInfo(subDirTarget, collection.remoteId());
1907     QVERIFY(fileInfo1_4.exists());
1908 
1909     // check for index preservation
1910     var = job->property("onDiskIndexInvalidated");
1911     QVERIFY(var.isValid());
1912     QCOMPARE(var.userType(), colListVar.userType());
1913 
1914     collections = var.value<Collection::List>();
1915     QCOMPARE((int)collections.count(), 1);
1916     QCOMPARE(collections.first(), collection);
1917 
1918     // get the items and check the flags (see data/README)
1919     itemFetch = mStore->fetchItems(collection);
1920     QVERIFY(itemFetch->exec());
1921     QCOMPARE(itemFetch->error(), 0);
1922 
1923     items = itemFetch->items();
1924     QCOMPARE((int)items.count(), 4);
1925     for (const Item &item : std::as_const(items)) {
1926         const auto flags{item.flags()};
1927         for (const QByteArray &flag : flags) {
1928             ++flagCounts[flag];
1929         }
1930     }
1931 
1932     QCOMPARE(flagCounts["\\SEEN"], 2);
1933     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1934     QCOMPARE(flagCounts["$TODO"], 1);
1935     flagCounts.clear();
1936 
1937     // move from mbox to grandchild
1938     collection1_1.setParentCollection(target);
1939 
1940     job = mStore->moveCollection(collection1_1, collection3);
1941 
1942     QVERIFY(job->exec());
1943     QCOMPARE(job->error(), 0);
1944 
1945     collection = job->collection();
1946     QCOMPARE(collection.remoteId(), collection1_1.remoteId());
1947     QCOMPARE(collection.parentCollection(), collection3);
1948 
1949     fileInfo1_1.refresh();
1950     QVERIFY(!fileInfo1_1.exists());
1951     fileInfo1_1 = QFileInfo(subDir3, collection.remoteId());
1952     QVERIFY(fileInfo1_1.exists());
1953 
1954     // check for index preservation
1955     var = job->property("onDiskIndexInvalidated");
1956     QVERIFY(var.isValid());
1957     QCOMPARE(var.userType(), colListVar.userType());
1958 
1959     collections = var.value<Collection::List>();
1960     QCOMPARE((int)collections.count(), 1);
1961     QCOMPARE(collections.first(), collection);
1962 
1963     // get the items and check the flags (see data/README)
1964     itemFetch = mStore->fetchItems(collection);
1965     QVERIFY(itemFetch->exec());
1966     QCOMPARE(itemFetch->error(), 0);
1967 
1968     items = itemFetch->items();
1969     QCOMPARE((int)items.count(), 4);
1970     for (const Item &item : std::as_const(items)) {
1971         const auto flags{item.flags()};
1972         for (const QByteArray &flag : flags) {
1973             ++flagCounts[flag];
1974         }
1975     }
1976 
1977     QCOMPARE(flagCounts["\\SEEN"], 2);
1978     QCOMPARE(flagCounts["\\FLAGGED"], 1);
1979     QCOMPARE(flagCounts["$TODO"], 1);
1980     flagCounts.clear();
1981 
1982     // move from maildir to grandchild
1983     collection1_2.setParentCollection(target);
1984 
1985     job = mStore->moveCollection(collection1_2, collection3);
1986 
1987     QVERIFY(job->exec());
1988     QCOMPARE(job->error(), 0);
1989 
1990     collection = job->collection();
1991     QCOMPARE(collection.remoteId(), collection1_2.remoteId());
1992     QCOMPARE(collection.parentCollection(), collection3);
1993 
1994     fileInfo1_2.refresh();
1995     QVERIFY(!fileInfo1_2.exists());
1996     fileInfo1_2 = QFileInfo(subDir3, collection.remoteId());
1997     QVERIFY(fileInfo1_2.exists());
1998 
1999     // check for index preservation
2000     var = job->property("onDiskIndexInvalidated");
2001     QVERIFY(var.isValid());
2002     QCOMPARE(var.userType(), colListVar.userType());
2003 
2004     collections = var.value<Collection::List>();
2005     QCOMPARE((int)collections.count(), 1);
2006     QCOMPARE(collections.first(), collection);
2007 
2008     // get the items and check the flags (see data/README)
2009     itemFetch = mStore->fetchItems(collection);
2010     QVERIFY(itemFetch->exec());
2011     QCOMPARE(itemFetch->error(), 0);
2012 
2013     items = itemFetch->items();
2014     QCOMPARE((int)items.count(), 4);
2015     for (const Item &item : std::as_const(items)) {
2016         const auto flags{item.flags()};
2017         for (const QByteArray &flag : flags) {
2018             ++flagCounts[flag];
2019         }
2020     }
2021 
2022     QCOMPARE(flagCounts["\\SEEN"], 2);
2023     QCOMPARE(flagCounts["\\FLAGGED"], 1);
2024     QCOMPARE(flagCounts["$TODO"], 1);
2025     flagCounts.clear();
2026 }
2027 
2028 QTEST_MAIN(CollectionMoveTest)
2029 
2030 #include "collectionmovetest.moc"