File indexing completed on 2024-12-22 04:57:32
0001 /* 0002 This file is part of the kpimutils library. 0003 0004 SPDX-FileCopyrightText: 2007 Till Adam <adam@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "testmaildir.h" 0010 0011 #include <memory> 0012 0013 #include <Akonadi/MessageFlags> 0014 0015 #include <QDir> 0016 #include <QFile> 0017 #include <QTemporaryDir> 0018 #include <QTest> 0019 0020 QTEST_MAIN(MaildirTest) 0021 0022 #include "../maildir.h" 0023 using namespace KPIM; 0024 0025 static const char *testDir = "libmaildir-unit-test"; 0026 static const char *testString = "From: theDukeOfMonmouth@uk.gov\n \nTo: theDukeOfBuccleuch@uk.gov\n\ntest\n"; 0027 static const char *testStringHeaders = "From: theDukeOfMonmouth@uk.gov\n \nTo: theDukeOfBuccleuch@uk.gov\n"; 0028 0029 void MaildirTest::init() 0030 { 0031 QString tmpPath(QDir::tempPath() + QLatin1Char('/') + QLatin1StringView(testDir)); 0032 QDir().mkpath(tmpPath); 0033 m_temp = new QTemporaryDir(tmpPath); 0034 0035 QDir temp(m_temp->path()); 0036 QVERIFY(temp.exists()); 0037 0038 temp.mkdir(QStringLiteral("new")); 0039 QVERIFY(temp.exists(QLatin1StringView("new"))); 0040 temp.mkdir(QStringLiteral("cur")); 0041 QVERIFY(temp.exists(QLatin1StringView("cur"))); 0042 temp.mkdir(QStringLiteral("tmp")); 0043 QVERIFY(temp.exists(QLatin1StringView("tmp"))); 0044 } 0045 0046 void MaildirTest::cleanup() 0047 { 0048 m_temp->remove(); 0049 QDir d(m_temp->path()); 0050 const QString subFolderPath(QStringLiteral(".%1.directory").arg(d.dirName())); 0051 QDir((subFolderPath)).removeRecursively(); 0052 0053 delete m_temp; 0054 m_temp = nullptr; 0055 } 0056 0057 void MaildirTest::fillDirectory(const QString &name, int limit) 0058 { 0059 QFile file; 0060 QDir::setCurrent(m_temp->path() + QLatin1Char('/') + name); 0061 for (int i = 0; i < limit; i++) { 0062 file.setFileName(QLatin1StringView("testmail-") + QString::number(i)); 0063 file.open(QIODevice::WriteOnly); 0064 file.write(testString); 0065 file.flush(); 0066 file.close(); 0067 } 0068 } 0069 0070 void MaildirTest::createSubFolders() 0071 { 0072 QDir d(m_temp->path()); 0073 const QString subFolderPath(QStringLiteral(".%1.directory").arg(d.dirName())); 0074 d.cdUp(); 0075 d.mkdir(subFolderPath); 0076 d.cd(subFolderPath); 0077 d.mkdir(QStringLiteral("foo")); 0078 d.mkdir(QStringLiteral("barbar")); 0079 d.mkdir(QStringLiteral("bazbaz")); 0080 } 0081 0082 void MaildirTest::fillNewDirectory() 0083 { 0084 fillDirectory(QStringLiteral("new"), 140); 0085 } 0086 0087 void MaildirTest::fillCurrentDirectory() 0088 { 0089 fillDirectory(QStringLiteral("cur"), 20); 0090 } 0091 0092 void MaildirTest::testMaildirInstantiation() 0093 { 0094 Maildir d(QStringLiteral("/foo/bar/Mail")); 0095 Maildir d2(d); 0096 Maildir d3; 0097 d3 = d; 0098 QVERIFY(d == d2); 0099 QVERIFY(d3 == d2); 0100 QVERIFY(d == d3); 0101 QCOMPARE(d.path(), QString(QLatin1StringView("/foo/bar/Mail"))); 0102 QCOMPARE(d.name(), QString(QLatin1StringView("Mail"))); 0103 0104 QVERIFY(!d.isValid(false)); 0105 0106 Maildir good(m_temp->path()); 0107 QVERIFY(good.isValid(false)); 0108 0109 QDir temp(m_temp->path()); 0110 temp.rmdir(QStringLiteral("new")); 0111 QVERIFY(!good.isValid(false)); 0112 QVERIFY(!good.lastError().isEmpty()); 0113 0114 Maildir root1(QStringLiteral("/foo/bar/Mail"), true); 0115 QVERIFY(root1.isRoot()); 0116 0117 Maildir root1Copy = root1; 0118 QCOMPARE(root1Copy.path(), root1.path()); 0119 QCOMPARE(root1Copy.isRoot(), root1.isRoot()); 0120 0121 // FIXME test insufficient permissions? 0122 } 0123 0124 void MaildirTest::testMaildirListing() 0125 { 0126 fillNewDirectory(); 0127 0128 Maildir d(m_temp->path()); 0129 QStringList entries = d.entryList(); 0130 0131 QCOMPARE(entries.count(), 140); 0132 0133 fillCurrentDirectory(); 0134 entries = d.entryList(); 0135 QCOMPARE(entries.count(), 160); 0136 } 0137 0138 void MaildirTest::testMaildirAccess() 0139 { 0140 fillCurrentDirectory(); 0141 Maildir d(m_temp->path()); 0142 QStringList entries = d.entryList(); 0143 QCOMPARE(entries.count(), 20); 0144 0145 QByteArray data = d.readEntry(entries[0]); 0146 QVERIFY(!data.isEmpty()); 0147 QCOMPARE(data, QByteArray(testString)); 0148 } 0149 0150 void MaildirTest::testMaildirReadHeaders() 0151 { 0152 fillCurrentDirectory(); 0153 Maildir d(m_temp->path()); 0154 QStringList entries = d.entryList(); 0155 QCOMPARE(entries.count(), 20); 0156 0157 QByteArray data = d.readEntryHeaders(entries[0]); 0158 QVERIFY(!data.isEmpty()); 0159 QCOMPARE(data, QByteArray(testStringHeaders)); 0160 } 0161 0162 void MaildirTest::testMaildirWrite() 0163 { 0164 fillCurrentDirectory(); 0165 Maildir d(m_temp->path()); 0166 QStringList entries = d.entryList(); 0167 QCOMPARE(entries.count(), 20); 0168 0169 QByteArray data = d.readEntry(entries[0]); 0170 QByteArray data2 = "changed\n"; 0171 QVERIFY(d.writeEntry(entries[0], data2)); 0172 QCOMPARE(data2, d.readEntry(entries[0])); 0173 } 0174 0175 void MaildirTest::testMaildirAppend() 0176 { 0177 Maildir d(m_temp->path()); 0178 QByteArray data = "newentry\n"; 0179 QString key = d.addEntry(data); 0180 QVERIFY(!key.isEmpty()); 0181 QCOMPARE(data, d.readEntry(key)); 0182 } 0183 0184 void MaildirTest::testMaildirCreation() 0185 { 0186 QString p(QStringLiteral("CREATETEST")); 0187 QString tmpPath(QDir::tempPath() + QLatin1Char('/') + p); 0188 QDir().mkpath(tmpPath); 0189 std::unique_ptr<QTemporaryDir> temp(new QTemporaryDir(tmpPath)); 0190 Maildir d(temp->path() + p); 0191 QVERIFY(!d.isValid(false)); 0192 d.create(); 0193 QVERIFY(d.isValid(false)); 0194 } 0195 0196 void MaildirTest::testMaildirRemoveEntry() 0197 { 0198 Maildir d(m_temp->path()); 0199 QByteArray data = "newentry\n"; 0200 QString key = d.addEntry(data); 0201 QVERIFY(!key.isEmpty()); 0202 QCOMPARE(data, d.readEntry(key)); 0203 QVERIFY(d.removeEntry(key)); 0204 QVERIFY(d.readEntry(key).isEmpty()); 0205 } 0206 0207 void MaildirTest::testMaildirListSubfolders() 0208 { 0209 fillNewDirectory(); 0210 0211 Maildir d(m_temp->path()); 0212 QStringList entries = d.subFolderList(); 0213 0214 QVERIFY(entries.isEmpty()); 0215 0216 createSubFolders(); 0217 0218 entries = d.subFolderList(); 0219 QVERIFY(!entries.isEmpty()); 0220 QCOMPARE(entries.count(), 3); 0221 } 0222 0223 void MaildirTest::testMaildirCreateSubfolder() 0224 { 0225 Maildir d(m_temp->path()); 0226 QStringList entries = d.subFolderList(); 0227 QVERIFY(entries.isEmpty()); 0228 0229 d.addSubFolder(QStringLiteral("subFolderTest")); 0230 entries = d.subFolderList(); 0231 QVERIFY(!entries.isEmpty()); 0232 QCOMPARE(entries.count(), 1); 0233 Maildir child = d.subFolder(entries.first()); 0234 QVERIFY(child.isValid(false)); 0235 } 0236 0237 void MaildirTest::testMaildirRemoveSubfolder() 0238 { 0239 Maildir d(m_temp->path()); 0240 QVERIFY(d.isValid(false)); 0241 0242 QString folderPath = d.addSubFolder(QStringLiteral("subFolderTest")); 0243 QVERIFY(!folderPath.isEmpty()); 0244 QVERIFY(folderPath.endsWith(QLatin1StringView(".directory/subFolderTest"))); 0245 bool removingWorked = d.removeSubFolder(QStringLiteral("subFolderTest")); 0246 QVERIFY(removingWorked); 0247 } 0248 0249 void MaildirTest::testMaildirRename() 0250 { 0251 Maildir d(m_temp->path()); 0252 QVERIFY(d.isValid(false)); 0253 0254 QString folderPath = d.addSubFolder(QStringLiteral("rename me!")); 0255 QVERIFY(!folderPath.isEmpty()); 0256 0257 Maildir d2(folderPath); 0258 QVERIFY(d2.isValid(false)); 0259 QVERIFY(d2.rename(QLatin1StringView("renamed"))); 0260 QCOMPARE(d2.name(), QString(QLatin1StringView("renamed"))); 0261 0262 // same again, should not fail 0263 QVERIFY(d2.rename(QLatin1StringView("renamed"))); 0264 QCOMPARE(d2.name(), QString(QLatin1StringView("renamed"))); 0265 0266 // already existing name 0267 QVERIFY(!d.addSubFolder(QLatin1StringView("this name is already taken")).isEmpty()); 0268 QVERIFY(!d2.rename(QLatin1StringView("this name is already taken"))); 0269 } 0270 0271 void MaildirTest::testMaildirMoveTo() 0272 { 0273 Maildir d(m_temp->path()); 0274 QVERIFY(d.isValid(false)); 0275 0276 QString folderPath1 = d.addSubFolder(QStringLiteral("child1")); 0277 QVERIFY(!folderPath1.isEmpty()); 0278 0279 Maildir d2(folderPath1); 0280 QVERIFY(d2.isValid(false)); 0281 0282 QDir d2Dir(d2.path()); 0283 QVERIFY(d2Dir.exists()); 0284 0285 QString folderPath11 = d2.addSubFolder(QStringLiteral("grandchild1")); 0286 0287 Maildir d21(folderPath11); 0288 QVERIFY(d21.isValid(false)); 0289 0290 QDir d2SubDir(Maildir::subDirPathForFolderPath(d2.path())); 0291 QVERIFY(d2SubDir.exists()); 0292 0293 QString folderPath2 = d.addSubFolder(QStringLiteral("child2")); 0294 QVERIFY(!folderPath2.isEmpty()); 0295 0296 Maildir d3(folderPath2); 0297 QVERIFY(d3.isValid(false)); 0298 0299 // move child1 to child2 0300 QVERIFY(d2.moveTo(d3)); 0301 0302 Maildir d31 = d3.subFolder(QStringLiteral("child1")); 0303 QVERIFY(d31.isValid(false)); 0304 0305 QVERIFY(!d2Dir.exists()); 0306 QVERIFY(!d2SubDir.exists()); 0307 0308 QDir d31Dir(d31.path()); 0309 QVERIFY(d31Dir.exists()); 0310 0311 QDir d31SubDir(Maildir::subDirPathForFolderPath(d31.path())); 0312 QVERIFY(d31SubDir.exists()); 0313 0314 Maildir d311 = d31.subFolder(QStringLiteral("grandchild1")); 0315 QVERIFY(d311.isValid(false)); 0316 0317 // try moving again 0318 d2 = Maildir(folderPath1); 0319 QVERIFY(!d2.isValid(false)); 0320 QVERIFY(!d2.moveTo(d3)); 0321 } 0322 0323 void MaildirTest::testMaildirFlagsReading() 0324 { 0325 QFile file; 0326 const QStringList markers = QStringList() << QStringLiteral("P") << QStringLiteral("R") << QStringLiteral("S") << QStringLiteral("F") 0327 << QStringLiteral("FPRS"); 0328 QDir::setCurrent(m_temp->path() + QStringLiteral("/cur")); 0329 for (int i = 0; i < 6; i++) { 0330 QString fileName = QLatin1StringView("testmail-") + QString::number(i); 0331 if (i < 5) { 0332 fileName += 0333 #ifdef Q_OS_WIN 0334 QLatin1StringView("!2,") 0335 #else 0336 QLatin1StringView(":2,") 0337 #endif 0338 + markers[i]; 0339 } 0340 file.setFileName(fileName); 0341 file.open(QIODevice::WriteOnly); 0342 file.write(testString); 0343 file.flush(); 0344 file.close(); 0345 } 0346 0347 Maildir d(m_temp->path()); 0348 QStringList entries = d.entryList(); 0349 // Maildir::entryList() doesn't sort for performance reasons, 0350 // do it here to make test sequence reliable. 0351 entries.sort(); 0352 0353 QCOMPARE(entries.count(), 6); 0354 0355 Akonadi::Item::Flags flags = d.readEntryFlags(entries[0]); 0356 QCOMPARE(flags.count(), 1); 0357 QVERIFY(flags.contains(Akonadi::MessageFlags::Forwarded)); 0358 0359 flags = d.readEntryFlags(entries[1]); 0360 QCOMPARE(flags.count(), 1); 0361 QVERIFY(flags.contains(Akonadi::MessageFlags::Replied)); 0362 0363 flags = d.readEntryFlags(entries[2]); 0364 QCOMPARE(flags.count(), 1); 0365 QVERIFY(flags.contains(Akonadi::MessageFlags::Seen)); 0366 0367 flags = d.readEntryFlags(entries[3]); 0368 QCOMPARE(flags.count(), 1); 0369 QVERIFY(flags.contains(Akonadi::MessageFlags::Flagged)); 0370 0371 flags = d.readEntryFlags(entries[4]); 0372 QCOMPARE(flags.count(), 4); 0373 QVERIFY(flags.contains(Akonadi::MessageFlags::Forwarded)); 0374 QVERIFY(flags.contains(Akonadi::MessageFlags::Replied)); 0375 QVERIFY(flags.contains(Akonadi::MessageFlags::Seen)); 0376 QVERIFY(flags.contains(Akonadi::MessageFlags::Flagged)); 0377 0378 flags = d.readEntryFlags(entries[5]); 0379 QVERIFY(flags.isEmpty()); 0380 } 0381 0382 void MaildirTest::testMaildirFlagsWriting_data() 0383 { 0384 QTest::addColumn<QString>("origDir"); 0385 QTest::addColumn<QString>("origFileName"); 0386 QTest::newRow("cur/") << "cur" 0387 << "testmail"; 0388 QTest::newRow("cur/S") << "cur" 0389 << "testmail:2,S"; // wrongly marked as "seen" on disk (#289428) 0390 QTest::newRow("new/") << "new" 0391 << "testmail"; 0392 QTest::newRow("new/S") << "new" 0393 << "testmail:2,S"; 0394 } 0395 0396 void MaildirTest::testMaildirFlagsWriting() 0397 { 0398 QFETCH(QString, origDir); 0399 QFETCH(QString, origFileName); 0400 0401 // create an initially new mail 0402 QFile file; 0403 QDir::setCurrent(m_temp->path()); 0404 file.setFileName(origDir + QLatin1Char('/') + origFileName); 0405 file.open(QIODevice::WriteOnly); 0406 file.write(testString); 0407 file.flush(); 0408 file.close(); 0409 0410 // add a single flag 0411 Maildir d(m_temp->path()); 0412 const QStringList entries = d.entryList(); 0413 QCOMPARE(entries.size(), 1); 0414 QVERIFY(QFile::exists(origDir + QLatin1Char('/') + entries[0])); 0415 const QString newKey = d.changeEntryFlags(entries[0], Akonadi::Item::Flags() << Akonadi::MessageFlags::Seen); 0416 // make sure the new key exists 0417 QCOMPARE(newKey, d.entryList()[0]); 0418 QVERIFY(QFile::exists(QStringLiteral("cur/") + newKey)); 0419 // and it's the right file 0420 QCOMPARE(d.readEntry(newKey), QByteArray(testString)); 0421 // now check the file name 0422 QVERIFY(newKey.endsWith(QLatin1StringView("2,S"))); 0423 // and more flags 0424 const QString newKey2 = d.changeEntryFlags(newKey, Akonadi::Item::Flags() << Akonadi::MessageFlags::Seen << Akonadi::MessageFlags::Replied); 0425 // check the file name, and the sorting of markers 0426 QVERIFY(newKey2.endsWith(QLatin1StringView("2,RS"))); 0427 QVERIFY(QFile::exists(QStringLiteral("cur/") + newKey2)); 0428 } 0429 0430 #include "moc_testmaildir.cpp"