1 /* 2 SPDX-FileCopyrightText: 2009 Andras Mantia <amantia@kde.org> 3 4 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com> 5 SPDX-FileContributor: Kevin Ottens <kevin@kdab.com> 6 7 SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include <QTest> 11 12 #include "kimap/loginjob.h" 13 #include "kimap/selectjob.h" 14 #include "kimap/session.h" 15 #include "kimaptest/fakeserver.h" 16 17 #include <QSignalSpy> 18 #include <QTest> 19 20 using Messages = QMap<qint64, KIMAP::Message>; 21 22 Q_DECLARE_METATYPE(KIMAP::Message) 23 Q_DECLARE_METATYPE(Messages) 24 25 class SelectJobTest : public QObject 26 { 27 Q_OBJECT 28 29 public: SelectJobTest()30 explicit SelectJobTest() 31 { 32 qRegisterMetaType<KIMAP::ImapSet>(); 33 qRegisterMetaType<KIMAP::Message>(); 34 qRegisterMetaType<QMap<qint64, KIMAP::Message>>("QMap<qint64,KIMAP::Message>"); 35 } 36 37 private Q_SLOTS: 38 testSingleSelect_data()39 void testSingleSelect_data() 40 { 41 QTest::addColumn<QList<QByteArray>>("scenario"); 42 QTest::addColumn<QList<QByteArray>>("flags"); 43 QTest::addColumn<QList<QByteArray>>("permanentflags"); 44 QTest::addColumn<int>("messagecount"); 45 QTest::addColumn<int>("recentcount"); 46 QTest::addColumn<int>("firstUnseenIndex"); 47 QTest::addColumn<qint64>("uidValidity"); 48 QTest::addColumn<qint64>("nextUid"); 49 QTest::addColumn<quint64>("highestmodseq"); 50 QTest::addColumn<bool>("condstoreEnabled"); 51 QTest::addColumn<bool>("readonly"); 52 QTest::addColumn<qint64>("lastUidvalidity"); 53 QTest::addColumn<quint64>("lastModseq"); 54 QTest::addColumn<KIMAP::ImapSet>("vanished"); 55 QTest::addColumn<Messages>("modified"); 56 57 QList<QByteArray> scenario; 58 QList<QByteArray> flags; 59 QList<QByteArray> permanentflags; 60 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\" (CONDSTORE)" 61 << "S: * 172 EXISTS" 62 << "S: * 1 RECENT" 63 << "S: * OK [UNSEEN 12] Message 12 is first unseen" 64 << "S: * OK [UIDVALIDITY 3857529045] UIDs valid" 65 << "S: * OK [UIDNEXT 4392] Predicted next UID" 66 << "S: * OK [HIGHESTMODSEQ 123456789]" 67 << R"(S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft))" 68 << R"(S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited)" 69 << "S: A000001 OK [READ-WRITE] SELECT completed"; 70 71 flags << "\\Answered" 72 << "\\Flagged" 73 << "\\Deleted" 74 << "\\Seen" 75 << "\\Draft"; 76 permanentflags << "\\Deleted" 77 << "\\Seen" 78 << "\\*"; 79 QTest::newRow("good") << scenario << flags << permanentflags << 172 << 1 << 12 << 3857529045LL << 4392LL << 123456789ULL << true << false << -1LL 80 << 0ULL << KIMAP::ImapSet{} << Messages{}; 81 82 scenario.clear(); 83 flags.clear(); 84 permanentflags.clear(); 85 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 86 << "S: A000001 BAD command unknown or arguments invalid"; 87 QTest::newRow("bad") << scenario << flags << permanentflags << 0 << 0 << 0 << 0LL << 0LL << 0ULL << false << false << -1LL << 0ULL << KIMAP::ImapSet{} 88 << Messages{}; 89 90 scenario.clear(); 91 flags.clear(); 92 permanentflags.clear(); 93 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 94 << "S: A000001 NO select failure"; 95 QTest::newRow("no") << scenario << flags << permanentflags << 0 << 0 << 0 << 0LL << 0LL << 0ULL << false << false << -1LL << 0ULL << KIMAP::ImapSet{} 96 << Messages{}; 97 98 scenario.clear(); 99 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\" (QRESYNC (67890007 90060115194045000))" 100 << "S: * 314 EXISTS" 101 << "S: * 15 RECENT" 102 << "S: * OK [UIDVALIDITY 67890007] UIDVALIDITY" 103 << "S: * OK [UIDNEXT 567] Predicted next UID" 104 << "S: * OK [HIGHESTMODSEQ 90060115205545359]" 105 << "S: * OK [UNSEEN 7] There are some unseen messages in the mailbox" 106 << R"(S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen))" 107 << R"(S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen \*)] Permanent flags)" 108 << "S: * VANISHED (EARLIER) 41,43:116,118,120:211,214:540" 109 << "S: * 49 FETCH (UID 117 FLAGS (\\Seen \\Answered) MODSEQ (90060115194045001))" 110 << "S: * 50 FETCH (UID 119 FLAGS (\\Draft $MDNSent) MODSEQ (90060115194045308))" 111 << "S: * 100 FETCH (UID 541 FLAGS (\\Seen $Forwarded) MODSEQ (90060115194045001))" 112 << "S: A000001 OK [READ-WRITE] mailbox selected"; 113 permanentflags = {"\\Answered", "\\Flagged", "\\Draft", "\\Deleted", "\\Seen", "\\*"}; 114 flags = {"\\Answered", "\\Flagged", "\\Draft", "\\Deleted", "\\Seen"}; 115 KIMAP::ImapSet vanished; 116 vanished.add(41); 117 vanished.add(KIMAP::ImapInterval{43, 116}); 118 vanished.add(118); 119 vanished.add(KIMAP::ImapInterval{120, 211}); 120 vanished.add(KIMAP::ImapInterval{214, 540}); 121 Messages modified = {{49, KIMAP::Message{117, 0, {"\\Seen", "\\Answered"}, {{"MODSEQ", QVariant{90060115194045001ULL}}}, {}, {}}}, 122 {50, KIMAP::Message{119, 0, {"\\Draft", "$MDNSent"}, {{"MODSEQ", QVariant{90060115194045308ULL}}}, {}, {}}}, 123 {100, KIMAP::Message{541, 0, {"\\Seen", "$Forwarded"}, {{"MODSEQ", QVariant{90060115194045001ULL}}}, {}, {}}}}; 124 QTest::newRow("QResync") << scenario << flags << permanentflags << 314 << 15 << 7 << 67890007LL << 567LL << 90060115205545359ULL << false << false 125 << 67890007LL << 90060115194045000ULL << vanished << modified; 126 } 127 testSingleSelect()128 void testSingleSelect() 129 { 130 QFETCH(QList<QByteArray>, scenario); 131 QFETCH(QList<QByteArray>, flags); 132 QFETCH(QList<QByteArray>, permanentflags); 133 QFETCH(int, messagecount); 134 QFETCH(int, recentcount); 135 QFETCH(int, firstUnseenIndex); 136 QFETCH(qint64, uidValidity); 137 QFETCH(qint64, nextUid); 138 QFETCH(quint64, highestmodseq); 139 QFETCH(bool, condstoreEnabled); 140 QFETCH(qint64, lastUidvalidity); 141 QFETCH(quint64, lastModseq); 142 QFETCH(KIMAP::ImapSet, vanished); 143 QFETCH(Messages, modified); 144 145 FakeServer fakeServer; 146 fakeServer.setScenario(scenario); 147 fakeServer.startAndWait(); 148 149 KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 150 151 auto job = new KIMAP::SelectJob(&session); 152 job->setCondstoreEnabled(condstoreEnabled); 153 job->setMailBox(QStringLiteral("INBOX")); 154 if (lastUidvalidity > -1 && lastModseq > 0) { 155 job->setQResync(lastUidvalidity, lastModseq); 156 } 157 158 QSignalSpy vanishedSpy(job, &KIMAP::SelectJob::vanished); 159 QVERIFY(vanishedSpy.isValid()); 160 161 QSignalSpy modifiedSpy(job, &KIMAP::SelectJob::modified); 162 QVERIFY(modifiedSpy.isValid()); 163 164 bool result = job->exec(); 165 QEXPECT_FAIL("bad", "Expected failure on BAD scenario", Continue); 166 QEXPECT_FAIL("no", "Expected failure on NO scenario", Continue); 167 QVERIFY(result); 168 if (result) { 169 QCOMPARE(job->flags(), flags); 170 QCOMPARE(job->permanentFlags(), permanentflags); 171 QCOMPARE(job->messageCount(), messagecount); 172 QCOMPARE(job->recentCount(), recentcount); 173 QCOMPARE(job->firstUnseenIndex(), firstUnseenIndex); 174 QCOMPARE(job->uidValidity(), uidValidity); 175 QCOMPARE(job->nextUid(), nextUid); 176 QCOMPARE(job->highestModSequence(), highestmodseq); 177 178 if (!vanished.isEmpty()) { 179 QCOMPARE(vanishedSpy.size(), 1); 180 QCOMPARE(vanishedSpy.at(0).at(0).value<KIMAP::ImapSet>(), vanished); 181 } 182 183 if (!modified.isEmpty()) { 184 Messages collectedModified; 185 for (const auto &modifiedSpyCatch : modifiedSpy) { 186 const auto msgs = modifiedSpyCatch.at(0).value<Messages>(); 187 for (auto it = msgs.begin(); it != msgs.end(); ++it) { 188 collectedModified.insert(it.key(), it.value()); 189 } 190 } 191 192 QCOMPARE(collectedModified, modified); 193 } 194 } 195 196 fakeServer.quit(); 197 } 198 testSeveralSelect()199 void testSeveralSelect() 200 { 201 FakeServer fakeServer; 202 fakeServer.setScenario(QList<QByteArray>() << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 203 << "S: A000001 OK [READ-WRITE] SELECT completed" 204 << "C: A000002 SELECT \"INBOX/Foo\"" 205 << "S: A000002 OK [READ-WRITE] SELECT completed"); 206 fakeServer.startAndWait(); 207 208 KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 209 210 auto job = new KIMAP::SelectJob(&session); 211 job->setMailBox(QStringLiteral("INBOX")); 212 QVERIFY(job->exec()); 213 214 job = new KIMAP::SelectJob(&session); 215 job->setMailBox(QStringLiteral("INBOX/Foo")); 216 QVERIFY(job->exec()); 217 } 218 testReadOnlySelect_data()219 void testReadOnlySelect_data() 220 { 221 QTest::addColumn<QList<QByteArray>>("scenario"); 222 QTest::addColumn<bool>("examine"); 223 QTest::addColumn<bool>("isReadOnly"); 224 225 { 226 QList<QByteArray> scenario; 227 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 228 << "S: A000001 OK [READ-WRITE] SELECT ok"; 229 QTest::newRow("SELECT rw") << scenario << false << false; 230 } 231 232 { 233 QList<QByteArray> scenario; 234 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 235 << "S: A000001 OK SELECT ok"; 236 QTest::newRow("SELECT rw (without code)") << scenario << false << false; 237 } 238 239 { 240 QList<QByteArray> scenario; 241 scenario << FakeServer::preauth() << "C: A000001 SELECT \"INBOX\"" 242 << "S: A000001 OK [READ-ONLY] SELECT ok"; 243 QTest::newRow("SELECT ro") << scenario << false << true; 244 } 245 246 { 247 QList<QByteArray> scenario; 248 scenario << FakeServer::preauth() << "C: A000001 EXAMINE \"INBOX\"" 249 << "S: A000001 OK [READ-ONLY] EXAMINE ok"; 250 QTest::newRow("EXAMINE ro") << scenario << true << true; 251 } 252 } 253 testReadOnlySelect()254 void testReadOnlySelect() 255 { 256 QFETCH(QList<QByteArray>, scenario); 257 QFETCH(bool, examine); 258 QFETCH(bool, isReadOnly); 259 260 FakeServer fakeServer; 261 fakeServer.setScenario(scenario); 262 fakeServer.startAndWait(); 263 264 KIMAP::Session session(QStringLiteral("127.0.0.1"), 5989); 265 266 KIMAP::SelectJob select(&session); 267 select.setOpenReadOnly(examine); 268 select.setMailBox(QStringLiteral("INBOX")); 269 QVERIFY(select.exec()); 270 271 QCOMPARE(select.isOpenReadOnly(), isReadOnly); 272 } 273 }; 274 275 QTEST_GUILESS_MAIN(SelectJobTest) 276 277 #include "selectjobtest.moc" 278