1 /*  This file is part of the KDE project
2     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
3     SPDX-FileContributor: Kevin Krammer <krake@kdab.com>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "mixedmaildirstore.h"
9 
10 #include "filestore/collectiondeletejob.h"
11 
12 #include "libmaildir/maildir.h"
13 
14 #include <QTemporaryDir>
15 
16 #include <QDir>
17 #include <QFileInfo>
18 #include <QTest>
19 
20 using namespace Akonadi;
21 
22 class CollectionDeleteTest : public QObject
23 {
24     Q_OBJECT
25 
26 public:
CollectionDeleteTest()27     CollectionDeleteTest()
28         : QObject()
29         , mStore(nullptr)
30         , mDir(nullptr)
31     {
32     }
33 
~CollectionDeleteTest()34     ~CollectionDeleteTest() override
35     {
36         delete mStore;
37         delete mDir;
38     }
39 
40 private:
41     MixedMaildirStore *mStore = nullptr;
42     QTemporaryDir *mDir = nullptr;
43 
44 private Q_SLOTS:
45     void init();
46     void cleanup();
47     void testNonExisting();
48     void testLeaves();
49     void testSubTrees();
50 };
51 
init()52 void CollectionDeleteTest::init()
53 {
54     mStore = new MixedMaildirStore;
55 
56     mDir = new QTemporaryDir;
57     QVERIFY(mDir->isValid());
58     QVERIFY(QDir(mDir->path()).exists());
59 }
60 
cleanup()61 void CollectionDeleteTest::cleanup()
62 {
63     delete mStore;
64     mStore = nullptr;
65     delete mDir;
66     mDir = nullptr;
67 }
68 
testNonExisting()69 void CollectionDeleteTest::testNonExisting()
70 {
71     KPIM::Maildir topLevelMd(mDir->path(), true);
72     QVERIFY(topLevelMd.isValid(false));
73 
74     KPIM::Maildir md1(topLevelMd.addSubFolder(QStringLiteral("collection1")), false);
75     KPIM::Maildir md1_2(md1.addSubFolder(QStringLiteral("collection1_2")), false);
76 
77     KPIM::Maildir md2(topLevelMd.addSubFolder(QStringLiteral("collection2")), false);
78 
79     // simulate mbox
80     QFileInfo fileInfo1(mDir->path(), QStringLiteral("collection3"));
81     QFile file1(fileInfo1.absoluteFilePath());
82     file1.open(QIODevice::WriteOnly);
83     file1.close();
84     QVERIFY(fileInfo1.exists());
85 
86     // simulate mbox with empty subtree
87     QFileInfo fileInfo2(mDir->path(), QStringLiteral("collection4"));
88     QFile file2(fileInfo2.absoluteFilePath());
89     file2.open(QIODevice::WriteOnly);
90     file2.close();
91     QVERIFY(fileInfo2.exists());
92 
93     QFileInfo subDirInfo2(KPIM::Maildir::subDirPathForFolderPath(fileInfo2.absoluteFilePath()));
94     QDir topDir(mDir->path());
95     QVERIFY(topDir.mkpath(subDirInfo2.absoluteFilePath()));
96 
97     mStore->setPath(mDir->path());
98 
99     FileStore::CollectionDeleteJob *job = nullptr;
100 
101     // test fail of deleting first level collection
102     Collection collection5;
103     collection5.setName(QStringLiteral("collection5"));
104     collection5.setRemoteId(QStringLiteral("collection5"));
105     collection5.setParentCollection(mStore->topLevelCollection());
106     job = mStore->deleteCollection(collection5);
107     QVERIFY(job != nullptr);
108 
109     QVERIFY(!job->exec());
110     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
111 
112     QCOMPARE(topLevelMd.subFolderList(), QStringList() << QStringLiteral("collection1") << QStringLiteral("collection2"));
113     QVERIFY(fileInfo1.exists());
114 
115     // test fail of deleting second level collection in maildir leaf parent
116     Collection collection2;
117     collection2.setName(QStringLiteral("collection2"));
118     collection2.setRemoteId(QStringLiteral("collection2"));
119     collection2.setParentCollection(mStore->topLevelCollection());
120 
121     Collection collection2_1;
122     collection2_1.setName(QStringLiteral("collection2_1"));
123     collection2_1.setRemoteId(QStringLiteral("collection2_1"));
124     collection2_1.setParentCollection(collection2);
125     job = mStore->deleteCollection(collection2_1);
126     QVERIFY(job != nullptr);
127 
128     QVERIFY(!job->exec());
129     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
130 
131     QCOMPARE(topLevelMd.subFolderList(), QStringList() << QStringLiteral("collection1") << QStringLiteral("collection2"));
132 
133     // test fail of deleting second level collection in maildir parent with subtree
134     Collection collection1;
135     collection1.setName(QStringLiteral("collection1"));
136     collection1.setRemoteId(QStringLiteral("collection1"));
137     collection1.setParentCollection(mStore->topLevelCollection());
138 
139     Collection collection1_1;
140     collection1_1.setName(QStringLiteral("collection1_1"));
141     collection1_1.setRemoteId(QStringLiteral("collection1_1"));
142     collection1_1.setParentCollection(collection1);
143     job = mStore->deleteCollection(collection1_1);
144     QVERIFY(job != nullptr);
145 
146     QVERIFY(!job->exec());
147     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
148 
149     QCOMPARE(topLevelMd.subFolderList(), QStringList() << QStringLiteral("collection1") << QStringLiteral("collection2"));
150     QCOMPARE(md1.subFolderList(), QStringList() << QStringLiteral("collection1_2"));
151 
152     // test fail of deleting second level collection in mbox leaf parent
153     Collection collection3;
154     collection3.setName(QStringLiteral("collection3"));
155     collection3.setRemoteId(QStringLiteral("collection3"));
156     collection3.setParentCollection(mStore->topLevelCollection());
157 
158     Collection collection3_1;
159     collection3_1.setName(QStringLiteral("collection3_1"));
160     collection3_1.setRemoteId(QStringLiteral("collection3_1"));
161     collection3_1.setParentCollection(collection3);
162     job = mStore->deleteCollection(collection3_1);
163     QVERIFY(job != nullptr);
164 
165     QVERIFY(!job->exec());
166     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
167 
168     QVERIFY(fileInfo1.exists());
169 
170     // test fail of deleting second level collection in mbox parent with subtree
171     Collection collection4;
172     collection4.setName(QStringLiteral("collection4"));
173     collection4.setRemoteId(QStringLiteral("collection4"));
174     collection4.setParentCollection(mStore->topLevelCollection());
175 
176     Collection collection4_1;
177     collection4_1.setName(QStringLiteral("collection4_1"));
178     collection4_1.setRemoteId(QStringLiteral("collection4_1"));
179     collection4_1.setParentCollection(collection4);
180     job = mStore->deleteCollection(collection4_1);
181     QVERIFY(job != nullptr);
182 
183     QVERIFY(!job->exec());
184     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
185 
186     QVERIFY(fileInfo2.exists());
187     QVERIFY(subDirInfo2.exists());
188 
189     // test fail of deleting second level collection with non existent parent
190     Collection collection5_1;
191     collection5_1.setName(QStringLiteral("collection5_1"));
192     collection5_1.setRemoteId(QStringLiteral("collection5_1"));
193     collection5_1.setParentCollection(collection5);
194     job = mStore->deleteCollection(collection5_1);
195     QVERIFY(job != nullptr);
196 
197     QVERIFY(!job->exec());
198     QCOMPARE(job->error(), (int)FileStore::Job::InvalidJobContext);
199 
200     QCOMPARE(topLevelMd.subFolderList(), QStringList() << QStringLiteral("collection1") << QStringLiteral("collection2"));
201     QVERIFY(fileInfo1.exists());
202     QCOMPARE(md1.subFolderList(), QStringList() << QStringLiteral("collection1_2"));
203 }
204 
testLeaves()205 void CollectionDeleteTest::testLeaves()
206 {
207     KPIM::Maildir topLevelMd(mDir->path(), true);
208     QVERIFY(topLevelMd.isValid(false));
209 
210     QDir topDir(mDir->path());
211 
212     KPIM::Maildir md1(topLevelMd.addSubFolder(QStringLiteral("collection1")), false);
213     KPIM::Maildir md1_2(md1.addSubFolder(QStringLiteral("collection1_2")), false);
214 
215     // simulate second level mbox in maildir parent
216     QFileInfo fileInfo1_1(KPIM::Maildir::subDirPathForFolderPath(md1.path()), QStringLiteral("collection1_1"));
217     QFile file1_1(fileInfo1_1.absoluteFilePath());
218     file1_1.open(QIODevice::WriteOnly);
219     file1_1.close();
220     QVERIFY(fileInfo1_1.exists());
221 
222     KPIM::Maildir md2(topLevelMd.addSubFolder(QStringLiteral("collection2")), false);
223 
224     // simulate first level mbox
225     QFileInfo fileInfo3(mDir->path(), QStringLiteral("collection3"));
226     QFile file3(fileInfo3.absoluteFilePath());
227     file3.open(QIODevice::WriteOnly);
228     file3.close();
229     QVERIFY(fileInfo3.exists());
230 
231     // simulate first level mbox with subtree
232     QFileInfo fileInfo4(mDir->path(), QStringLiteral("collection4"));
233     QFile file4(fileInfo4.absoluteFilePath());
234     file4.open(QIODevice::WriteOnly);
235     file4.close();
236     QVERIFY(fileInfo4.exists());
237 
238     QFileInfo subDirInfo4(KPIM::Maildir::subDirPathForFolderPath(fileInfo4.absoluteFilePath()));
239     QVERIFY(topDir.mkpath(subDirInfo4.absoluteFilePath()));
240 
241     KPIM::Maildir md4(subDirInfo4.absoluteFilePath(), true);
242     KPIM::Maildir md4_1(md4.addSubFolder(QStringLiteral("collection4_1")), false);
243 
244     // simulate second level mbox in mbox parent
245     QFileInfo fileInfo4_2(subDirInfo4.absoluteFilePath(), QStringLiteral("collection4_2"));
246     QFile file4_2(fileInfo4_2.absoluteFilePath());
247     file4_2.open(QIODevice::WriteOnly);
248     file4_2.close();
249     QVERIFY(fileInfo4_2.exists());
250 
251     mStore->setPath(mDir->path());
252 
253     FileStore::CollectionDeleteJob *job = nullptr;
254 
255     // test second level leaves in maildir parent
256     Collection collection1;
257     collection1.setName(QStringLiteral("collection1"));
258     collection1.setRemoteId(QStringLiteral("collection1"));
259     collection1.setParentCollection(mStore->topLevelCollection());
260 
261     Collection collection1_1;
262     collection1_1.setName(QStringLiteral("collection1_1"));
263     collection1_1.setRemoteId(QStringLiteral("collection1_1"));
264     collection1_1.setParentCollection(collection1);
265     job = mStore->deleteCollection(collection1_1);
266     QVERIFY(job != nullptr);
267 
268     QVERIFY(job->exec());
269     QCOMPARE(job->error(), 0);
270 
271     fileInfo1_1.refresh();
272     QVERIFY(!fileInfo1_1.exists());
273 
274     Collection collection1_2;
275     collection1_2.setName(QStringLiteral("collection1_2"));
276     collection1_2.setRemoteId(QStringLiteral("collection1_2"));
277     collection1_2.setParentCollection(collection1);
278     job = mStore->deleteCollection(collection1_2);
279     QVERIFY(job != nullptr);
280 
281     QVERIFY(job->exec());
282     QCOMPARE(job->error(), 0);
283 
284     QVERIFY(!md1_2.isValid(false));
285     QCOMPARE(md1.subFolderList(), QStringList());
286 
287     // test second level leaves in mbox parent
288     Collection collection4;
289     collection4.setName(QStringLiteral("collection4"));
290     collection4.setRemoteId(QStringLiteral("collection4"));
291     collection4.setParentCollection(mStore->topLevelCollection());
292 
293     Collection collection4_1;
294     collection4_1.setName(QStringLiteral("collection4_1"));
295     collection4_1.setRemoteId(QStringLiteral("collection4_1"));
296     collection4_1.setParentCollection(collection4);
297     job = mStore->deleteCollection(collection4_1);
298     QVERIFY(job != nullptr);
299 
300     QVERIFY(job->exec());
301     QCOMPARE(job->error(), 0);
302 
303     QVERIFY(!md4_1.isValid(false));
304     QCOMPARE(md4.subFolderList(), QStringList());
305 
306     Collection collection4_2;
307     collection4_2.setName(QStringLiteral("collection4_2"));
308     collection4_2.setRemoteId(QStringLiteral("collection4_2"));
309     collection4_2.setParentCollection(collection4);
310     job = mStore->deleteCollection(collection4_2);
311     QVERIFY(job != nullptr);
312 
313     QVERIFY(job->exec());
314     QCOMPARE(job->error(), 0);
315 
316     fileInfo4_2.refresh();
317     QVERIFY(!fileInfo4_2.exists());
318 
319     // test deleting of first level leaves
320     Collection collection2;
321     collection2.setName(QStringLiteral("collection2"));
322     collection2.setRemoteId(QStringLiteral("collection2"));
323     collection2.setParentCollection(mStore->topLevelCollection());
324 
325     job = mStore->deleteCollection(collection2);
326     QVERIFY(job != nullptr);
327 
328     QVERIFY(job->exec());
329     QCOMPARE(job->error(), 0);
330 
331     QVERIFY(!md2.isValid(false));
332     QCOMPARE(topLevelMd.subFolderList(), QStringList() << QStringLiteral("collection1"));
333 
334     Collection collection3;
335     collection3.setName(QStringLiteral("collection3"));
336     collection3.setRemoteId(QStringLiteral("collection3"));
337     collection3.setParentCollection(mStore->topLevelCollection());
338 
339     job = mStore->deleteCollection(collection3);
340     QVERIFY(job != nullptr);
341 
342     QVERIFY(job->exec());
343     QCOMPARE(job->error(), 0);
344 
345     fileInfo3.refresh();
346     QVERIFY(!fileInfo3.exists());
347 
348     // test deleting of first level leaves with empty subtrees
349     QFileInfo subDirInfo1(KPIM::Maildir::subDirPathForFolderPath(md1.path()));
350     QVERIFY(subDirInfo1.exists());
351 
352     job = mStore->deleteCollection(collection1);
353     QVERIFY(job != nullptr);
354 
355     QVERIFY(job->exec());
356     QCOMPARE(job->error(), 0);
357 
358     QVERIFY(!md1.isValid(false));
359     subDirInfo1.refresh();
360     QVERIFY(!subDirInfo1.exists());
361     QCOMPARE(topLevelMd.subFolderList(), QStringList());
362 
363     job = mStore->deleteCollection(collection4);
364     QVERIFY(job != nullptr);
365 
366     QVERIFY(job->exec());
367     QCOMPARE(job->error(), 0);
368 
369     fileInfo4.refresh();
370     QVERIFY(!fileInfo4.exists());
371     subDirInfo4.refresh();
372     QVERIFY(!subDirInfo4.exists());
373 }
374 
testSubTrees()375 void CollectionDeleteTest::testSubTrees()
376 {
377     KPIM::Maildir topLevelMd(mDir->path(), true);
378     QVERIFY(topLevelMd.isValid(false));
379 
380     QDir topDir(mDir->path());
381 
382     KPIM::Maildir md1(topLevelMd.addSubFolder(QStringLiteral("collection1")), false);
383     KPIM::Maildir md1_2(md1.addSubFolder(QStringLiteral("collection1_2")), false);
384 
385     // simulate second level mbox in maildir parent
386     QFileInfo fileInfo1_1(KPIM::Maildir::subDirPathForFolderPath(md1.path()), QStringLiteral("collection1_1"));
387     QFile file1_1(fileInfo1_1.absoluteFilePath());
388     file1_1.open(QIODevice::WriteOnly);
389     file1_1.close();
390     QVERIFY(fileInfo1_1.exists());
391 
392     // simulate first level mbox with subtree
393     QFileInfo fileInfo2(mDir->path(), QStringLiteral("collection2"));
394     QFile file2(fileInfo2.absoluteFilePath());
395     file2.open(QIODevice::WriteOnly);
396     file2.close();
397     QVERIFY(fileInfo2.exists());
398 
399     QFileInfo subDirInfo2(KPIM::Maildir::subDirPathForFolderPath(fileInfo2.absoluteFilePath()));
400     QVERIFY(topDir.mkpath(subDirInfo2.absoluteFilePath()));
401 
402     KPIM::Maildir md2(subDirInfo2.absoluteFilePath(), true);
403     KPIM::Maildir md2_1(md2.addSubFolder(QStringLiteral("collection2_1")), false);
404 
405     // simulate second level mbox in mbox parent
406     QFileInfo fileInfo2_2(subDirInfo2.absoluteFilePath(), QStringLiteral("collection2_2"));
407     QFile file2_2(fileInfo2_2.absoluteFilePath());
408     file2_2.open(QIODevice::WriteOnly);
409     file2_2.close();
410     QVERIFY(fileInfo2_2.exists());
411 
412     mStore->setPath(mDir->path());
413 
414     FileStore::CollectionDeleteJob *job = nullptr;
415 
416     // test deleting maildir subtree
417     QFileInfo subDirInfo1(KPIM::Maildir::subDirPathForFolderPath(md1.path()));
418     QVERIFY(subDirInfo1.exists());
419 
420     Collection collection1;
421     collection1.setName(QStringLiteral("collection1"));
422     collection1.setRemoteId(QStringLiteral("collection1"));
423     collection1.setParentCollection(mStore->topLevelCollection());
424 
425     job = mStore->deleteCollection(collection1);
426 
427     QVERIFY(job->exec());
428     QCOMPARE(job->error(), 0);
429 
430     QVERIFY(!md1.isValid(false));
431     QVERIFY(!md1_2.isValid(false));
432     fileInfo1_1.refresh();
433     QVERIFY(!fileInfo1_1.exists());
434 
435     // test deleting mbox subtree
436     Collection collection2;
437     collection2.setName(QStringLiteral("collection2"));
438     collection2.setRemoteId(QStringLiteral("collection2"));
439     collection2.setParentCollection(mStore->topLevelCollection());
440 
441     job = mStore->deleteCollection(collection2);
442 
443     QVERIFY(job->exec());
444     QCOMPARE(job->error(), 0);
445 
446     fileInfo2.refresh();
447     QVERIFY(!fileInfo2.exists());
448     QVERIFY(!md2_1.isValid(false));
449     fileInfo2_2.refresh();
450     QVERIFY(!fileInfo2_2.exists());
451     QVERIFY(!subDirInfo2.exists());
452 }
453 
454 QTEST_MAIN(CollectionDeleteTest)
455 
456 #include "collectiondeletetest.moc"
457