1 /* Copyright (C) 2014-2015 Stephan Platz <trojita@paalsteek.de>
3 This file is part of the Trojita Qt IMAP e-mail client,
4 http://trojita.flaska.net/
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <QtTest/QtTest>
25 #include "test_Cryptography_PGP.h"
26 #include "configure.cmake.h"
27 #include "crypto_test_data.h"
28 #include "Cryptography/MessageModel.h"
29 #include "Imap/data.h"
30 #include "Imap/Model/ItemRoles.h"
31 #include "Streams/FakeSocket.h"
33 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
34 # ifdef TROJITA_HAVE_GPGMEPP
35 # include "Cryptography/GpgMe++.h"
40 * * decrypt with not yet valid key
41 * * verify valid signature
42 * * verify corrupted signature
43 * * verify signature of modified text
44 * * verify signature with expired key
45 * * verify signature with not yet valid key
46 * * verify signature with unknown key
50 void CryptographyPGPTest::initTestCase()
52 LibMailboxSync::initTestCase();
53 if (!qputenv("GNUPGHOME", QByteArray(QCoreApplication::applicationDirPath().toUtf8() + "/keys").constData())) {
54 QFAIL("Unable to set GNUPGHOME environment variable");
58 void CryptographyPGPTest::testDecryption()
60 QFETCH(QByteArray
, bodystructure
);
61 QFETCH(QByteArray
, cyphertext
);
62 QFETCH(QByteArray
, plaintext
);
63 QFETCH(QString
, from
);
64 QFETCH(bool, successful
);
66 // By default, there's a 50ms delay between the time we request a part download and the time it actually happens.
67 // That's too long for a unit test.
68 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
70 helperSyncBNoMessages();
71 cServer("* 1 EXISTS\r\n");
72 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
73 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
75 QCOMPARE(model
->rowCount(msgListB
), 1);
76 QModelIndex msg
= msgListB
.child(0, 0);
77 QVERIFY(msg
.isValid());
78 QCOMPARE(model
->rowCount(msg
), 0);
79 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
80 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), from
, bodystructure
)
81 + t
.last("OK fetched\r\n"));
83 QVERIFY(model
->rowCount(msg
) > 0);
84 Cryptography::MessageModel
msgModel(0, msg
);
85 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
86 # ifdef TROJITA_HAVE_GPGMEPP
87 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
90 QModelIndex mappedMsg
= msgModel
.index(0,0);
91 QVERIFY(mappedMsg
.isValid());
92 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
94 QModelIndex data
= mappedMsg
.child(0, 0);
95 QVERIFY(data
.isValid());
96 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
97 QCOMPARE(msgModel
.rowCount(data
), 0);
98 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
100 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[2\\] BODY\\.PEEK\\[1\\]|BODY.PEEK\\[1\\] BODY\\.PEEK\\[2\\])\\)"));
101 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(cyphertext
) + " BODY[1] " + asLiteral("Version: 1\r\n") + ")\r\n"
102 + t
.last("OK fetched"));
104 QSignalSpy
qcaSuccessSpy(&msgModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)));
105 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
108 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && i
++ < 1000) {
111 // allow for event processing, so that the model can retrieve the results
112 QCoreApplication::processEvents();
114 if (!qcaErrorSpy
.isEmpty() && successful
) {
115 qDebug() << "Unexpected failure in crypto";
116 for (int i
= 0; i
< qcaErrorSpy
.size(); ++i
) {
117 qDebug() << qcaErrorSpy
[i
][1].toString();
118 qDebug() << qcaErrorSpy
[i
][2].toString();
123 QCOMPARE(qcaErrorSpy
.empty(), successful
);
124 QCOMPARE(qcaSuccessSpy
.empty(), !successful
);
127 QVERIFY(data
.data(Imap::Mailbox::RoleIsFetched
).toBool());
130 QVERIFY(errorSpy
->empty());
132 QCOMPARE(msgModel
.rowCount(data
), 2);
133 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), true);
135 QCOMPARE(data
.child(0, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/pgp-encrypted"));
136 QCOMPARE(data
.child(1, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/octet-stream"));
139 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
143 void CryptographyPGPTest::testDecryption_data()
145 QTest::addColumn
<QByteArray
>("bodystructure");
146 QTest::addColumn
<QByteArray
>("cyphertext");
147 QTest::addColumn
<QByteArray
>("plaintext");
148 QTest::addColumn
<QString
>("from");
149 QTest::addColumn
<bool>("successful");
151 // everything is correct
152 QTest::newRow("valid")
155 << QByteArray("plaintext")
156 << QStringLiteral("valid@test.trojita.flaska.net")
160 QTest::newRow("invalid")
163 << QByteArray("plaintext")
164 << QStringLiteral("valid@test.trojita.flaska.net")
167 // the key used for encryption is expired
168 QTest::newRow("expiredKey")
171 << QByteArray("plaintext")
172 // NOTE (jkt): This is how my QCA/2.1.0.3, GnuPG/2.0.28 behaves.
173 << QStringLiteral("valid@test.trojita.flaska.net")
176 // we don't have any key which is needed for encryption
177 QTest::newRow("unknownKey")
180 << QByteArray("plaintext")
181 << QStringLiteral("valid@test.trojita.flaska.net")
185 /** @short What happens when ENVELOPE doesn't arrive at the time that parts are already there? */
186 void CryptographyPGPTest::testDecryptWithoutEnvelope()
188 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
189 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
191 helperSyncBNoMessages();
192 cServer("* 1 EXISTS\r\n");
193 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
194 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
195 QCOMPARE(model
->rowCount(msgListB
), 1);
196 QModelIndex msg
= msgListB
.child(0, 0);
197 QVERIFY(msg
.isValid());
198 Cryptography::MessageModel
msgModel(0, msg
);
199 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
201 QCOMPARE(model
->rowCount(msg
), 0);
202 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
203 cServer("* 1 FETCH (UID 333 BODYSTRUCTURE (" + bsEncrypted
+ "))\r\n" + t
.last("OK fetched\r\n"));
204 // notice that the ENVELOPE never arrived
206 QVERIFY(model
->rowCount(msg
) > 0);
207 QModelIndex mappedMsg
= msgModel
.index(0,0);
208 QVERIFY(mappedMsg
.isValid());
209 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
211 QModelIndex data
= mappedMsg
.child(0, 0);
212 QVERIFY(data
.isValid());
213 QCOMPARE(msgModel
.rowCount(data
), 0);
214 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
216 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[2\\] BODY\\.PEEK\\[1\\]|BODY.PEEK\\[1\\] BODY\\.PEEK\\[2\\])\\)"));
217 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(encValid
) + " BODY[1] " + asLiteral("Version: 1\r\n") + ")\r\n"
218 + t
.last("OK fetched"));
220 QSignalSpy
qcaSuccessSpy(&msgModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)));
221 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
224 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && i
++ < 1000) {
227 // allow for event processing, so that the model can retrieve the results
228 QCoreApplication::processEvents();
230 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool(), false);
231 QVERIFY(qcaSuccessSpy
.isEmpty());
232 QVERIFY(qcaErrorSpy
.isEmpty());
234 QVERIFY(!data
.data(Imap::Mailbox::RoleIsFetched
).toBool()); // because the ENVELOPE hasn't arrived yet
237 QVERIFY(errorSpy
->empty());
239 QSKIP("Cannot test without GpgME++ support");
243 void CryptographyPGPTest::testVerification()
245 QFETCH(QByteArray
, signature
);
246 QFETCH(QByteArray
, ptMimeHdr
);
247 QFETCH(QByteArray
, plaintext
);
248 QFETCH(bool, successful
);
249 QFETCH(QString
, from
);
250 QFETCH(QString
, tldr
);
251 QFETCH(QString
, longDesc
);
252 QFETCH(bool, validDisregardingTrust
);
253 QFETCH(bool, validCompletely
);
255 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
256 helperSyncBNoMessages();
257 cServer("* 1 EXISTS\r\n");
258 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
259 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
260 QCOMPARE(model
->rowCount(msgListB
), 1);
261 QModelIndex msg
= msgListB
.child(0, 0);
262 QVERIFY(msg
.isValid());
263 QCOMPARE(model
->rowCount(msg
), 0);
264 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
265 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), from
, QStringLiteral(
266 "(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 423 14 NIL NIL NIL NIL)"
267 "(\"application\" \"pgp-signature\" NIL NIL NIL \"7bit\" 851 NIL NIL NIL NIL)"
268 " \"signed\" (\"boundary\" \"=-=-=\" \"micalg\" \"pgp-sha256\" \"protocol\" \"application/pgp-signature\")"
270 + t
.last("OK fetched\r\n"));
272 QVERIFY(model
->rowCount(msg
) > 0);
273 Cryptography::MessageModel
msgModel(0, msg
);
274 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
275 # ifdef TROJITA_HAVE_GPGMEPP
276 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
279 QModelIndex mappedMsg
= msgModel
.index(0,0);
280 QVERIFY(mappedMsg
.isValid());
281 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
283 QModelIndex data
= mappedMsg
.child(0, 0);
284 QVERIFY(data
.isValid());
285 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
286 QCOMPARE(msgModel
.rowCount(data
), 0);
287 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
289 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[(2|1|1\\.MIME)\\] ?){3}\\)"));
290 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(signature
) + " BODY[1] " + asLiteral(plaintext
)
291 + " BODY[1.MIME] " + asLiteral(ptMimeHdr
) + ")\r\n"
292 + t
.last("OK fetched"));
294 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
297 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && qcaErrorSpy
.empty() && i
++ < 1000) {
300 // allow for event processing, so that the model can retrieve the results
301 QCoreApplication::processEvents();
303 if (!qcaErrorSpy
.isEmpty() && successful
) {
304 qDebug() << "Unexpected failure in crypto";
305 for (int i
= 0; i
< qcaErrorSpy
.size(); ++i
) {
306 qDebug() << qcaErrorSpy
[i
][1].toString();
307 qDebug() << qcaErrorSpy
[i
][2].toString();
311 QCOMPARE(qcaErrorSpy
.empty(), successful
);
312 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoTLDR
).toString(), tldr
);
313 auto actualLongDesc
= data
.data(Imap::Mailbox::RolePartCryptoDetailedMessage
).toString();
314 if (!actualLongDesc
.startsWith(longDesc
)) {
315 QCOMPARE(actualLongDesc
, longDesc
); // let's reuse this for debug output, and don't be scared about the misleading implications
318 QCOMPARE(data
.data(Imap::Mailbox::RolePartSignatureVerifySupported
).toBool(), successful
);
319 QCOMPARE(data
.data(Imap::Mailbox::RolePartSignatureValidDisregardingTrust
).toBool(), validDisregardingTrust
);
320 QCOMPARE(data
.data(Imap::Mailbox::RolePartSignatureValidTrusted
).toBool(), validCompletely
);
321 QCOMPARE(data
.data(Imap::Mailbox::RolePartMimeType
).toByteArray(), QByteArray("multipart/signed"));
322 QVERIFY(data
.data(Imap::Mailbox::RoleIsFetched
).toBool() == successful
);
324 auto partIdx
= data
.child(0, 0);
325 QCOMPARE(partIdx
.data(Imap::Mailbox::RolePartMimeType
).toByteArray(), QByteArray("text/plain"));
326 QCOMPARE(partIdx
.data(Imap::Mailbox::RolePartUnicodeText
).toString(), QString::fromUtf8(plaintext
));
329 QVERIFY(errorSpy
->empty());
331 QCOMPARE(msgModel
.rowCount(data
), 2);
332 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), true);
334 QCOMPARE(data
.child(0, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/pgp-encrypted"));
335 QCOMPARE(data
.child(1, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/octet-stream"));
338 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
342 void CryptographyPGPTest::testVerification_data()
344 QTest::addColumn
<QByteArray
>("signature");
345 QTest::addColumn
<QByteArray
>("ptMimeHdr");
346 QTest::addColumn
<QByteArray
>("plaintext");
347 QTest::addColumn
<bool>("successful");
348 QTest::addColumn
<QString
>("from");
349 QTest::addColumn
<QString
>("tldr");
350 QTest::addColumn
<QString
>("longDesc");
351 QTest::addColumn
<bool>("validDisregardingTrust");
352 QTest::addColumn
<bool>("validCompletely");
354 QByteArray ptMimeHdr
= QByteArrayLiteral("Content-Type: text/plain\r\n\r\n");
356 // everything is correct
357 QTest::newRow("valid-me")
360 << QByteArray("plaintext\r\n")
362 << QStringLiteral("valid@test.trojita.flaska.net")
363 << QStringLiteral("Verified signature")
364 << QStringLiteral("Verified signature from Valid <valid@test.trojita.flaska.net> (")
368 // my signature, but a different identity
369 QTest::newRow("my-signature-different-identity")
372 << QByteArray("plaintext\r\n")
374 << QStringLiteral("evil@example.org")
375 << QStringLiteral("Signed by stranger")
376 << QStringLiteral("Verified signature, but the signer is someone else:\nValid <valid@test.trojita.flaska.net> (")
380 // my signature, different data
381 QTest::newRow("my-signature-different-data")
384 << QByteArray("I will pay you right now\r\n")
386 << QStringLiteral("valid@test.trojita.flaska.net")
387 << QStringLiteral("Bad signature")
388 << QStringLiteral("Bad signature by Valid <valid@test.trojita.flaska.net> (")
392 // A missing Content-Type header (and also an invalid signature)
393 QTest::newRow("invalid-implicit-content-type")
395 << QByteArrayLiteral("Content-Transfer-Encoding: 8bit\r\n\r\n")
396 << QByteArray("plaintext\r\n")
398 << QStringLiteral("valid@test.trojita.flaska.net")
399 << QStringLiteral("Bad signature")
400 << QStringLiteral("Bad signature by Valid <valid@test.trojita.flaska.net> (")
405 void CryptographyPGPTest::testMalformed()
407 QFETCH(QByteArray
, bodystructure
);
408 QFETCH(int, rowCount
);
409 QFETCH(QString
, tldr
);
410 QFETCH(QString
, detail
);
412 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
413 helperSyncBNoMessages();
414 cServer("* 1 EXISTS\r\n");
415 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
416 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
417 QCOMPARE(model
->rowCount(msgListB
), 1);
418 QModelIndex msg
= msgListB
.child(0, 0);
419 QVERIFY(msg
.isValid());
420 QCOMPARE(model
->rowCount(msg
), 0);
421 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
422 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), QStringLiteral("foo@example.org"), QString::fromUtf8(bodystructure
))
423 + t
.last("OK fetched\r\n"));
425 QVERIFY(model
->rowCount(msg
) > 0);
426 Cryptography::MessageModel
msgModel(0, msg
);
427 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
428 # ifdef TROJITA_HAVE_GPGMEPP
429 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
432 QModelIndex mappedMsg
= msgModel
.index(0,0);
433 QVERIFY(mappedMsg
.isValid());
434 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
436 QModelIndex data
= mappedMsg
.child(0, 0);
437 QVERIFY(data
.isValid());
438 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
439 QCoreApplication::processEvents();
440 QCOMPARE(msgModel
.rowCount(data
), rowCount
);
441 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoTLDR
).toString(), tldr
);
442 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoDetailedMessage
).toString(), detail
);
445 QVERIFY(errorSpy
->empty());
447 QCOMPARE(msgModel
.rowCount(data
), rowCount
);
448 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), true);
452 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
456 void CryptographyPGPTest::testMalformed_data()
458 QTest::addColumn
<QByteArray
>("bodystructure");
459 QTest::addColumn
<int>("rowCount");
460 QTest::addColumn
<QString
>("tldr");
461 QTest::addColumn
<QString
>("detail");
463 // Due to the missing "protocol", the part replacer won't even react
464 QTest::newRow("signed-missing-protocol-micalg")
465 << bsMultipartSignedTextPlain
470 // A mailing list has stripped the signature
471 QTest::newRow("signed-ml-stripped-gpg-signature")
472 << QByteArray("(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 423 14 NIL NIL NIL NIL)"
473 " \"signed\" (\"boundary\" \"=-=-=\" \"micalg\" \"pgp-sha256\" \"protocol\" \"application/pgp-signature\")"
476 << QStringLiteral("Malformed Signed Message")
477 << QStringLiteral("Expected 2 parts, but found 1.");
481 /** @short Check operation when some data are not available */
482 void CryptographyPGPTest::testOffline()
484 QFETCH(QByteArray
, bodystructure
);
485 QFETCH(QByteArray
, fetchRegex
);
487 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
488 helperSyncBNoMessages();
489 cServer("* 1 EXISTS\r\n");
490 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
491 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
492 QCOMPARE(model
->rowCount(msgListB
), 1);
493 QModelIndex msg
= msgListB
.child(0, 0);
494 QVERIFY(msg
.isValid());
495 QCOMPARE(model
->rowCount(msg
), 0);
496 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
497 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), QStringLiteral("foo@example.org"), bodystructure
)
498 + t
.last("OK fetched\r\n"));
500 QVERIFY(model
->rowCount(msg
) > 0);
501 Cryptography::MessageModel
msgModel(0, msg
);
502 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
503 # ifdef TROJITA_HAVE_GPGMEPP
504 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
507 QModelIndex mappedMsg
= msgModel
.index(0,0);
508 QVERIFY(mappedMsg
.isValid());
509 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
511 QModelIndex data
= mappedMsg
.child(0, 0);
512 QVERIFY(data
.isValid());
513 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
514 QCOMPARE(msgModel
.rowCount(mappedMsg
), 1);
515 QCOMPARE(msgModel
.rowCount(data
), 0);
516 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
518 cClientRegExp(t
.mk(fetchRegex
));
519 auto fetchResp
= t
.last("NO offline\r\n");
520 LibMailboxSync::setModelNetworkPolicy(model
, Imap::Mailbox::NETWORK_OFFLINE
);
521 cClient(t
.mk("LOGOUT\r\n"));
522 cServer(fetchResp
+ t
.last("OK logout\r\n"));
524 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
527 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && qcaErrorSpy
.empty() && i
++ < 1000) {
530 // allow for event processing, so that the model can retrieve the results
531 QCoreApplication::processEvents();
533 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
), QVariant(false));
534 QCOMPARE(data
.data(Imap::Mailbox::RolePartCryptoTLDR
), QVariant(QStringLiteral("Data Unavailable")));
535 QCOMPARE(msgModel
.rowCount(data
), 2);
537 if (!qcaErrorSpy
.isEmpty()) {
538 qDebug() << "Unexpected failure in crypto";
539 for (int i
= 0; i
< qcaErrorSpy
.size(); ++i
) {
540 qDebug() << qcaErrorSpy
[i
][1].toString();
541 qDebug() << qcaErrorSpy
[i
][2].toString();
545 // We're offline, we cannot call cEmpty(), that would assert-crash due to no active parsers
548 QVERIFY(errorSpy
->empty());
550 QCOMPARE(msgModel
.rowCount(data
), 2);
551 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), true);
554 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
558 void CryptographyPGPTest::testOffline_data()
560 QTest::addColumn
<QByteArray
>("bodystructure");
561 QTest::addColumn
<QByteArray
>("fetchRegex");
563 QTest::newRow("signed")
564 << QByteArray("(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 423 14 NIL NIL NIL NIL)"
565 "(\"application\" \"pgp-signature\" NIL NIL NIL \"7bit\" 851 NIL NIL NIL NIL)"
566 " \"signed\" (\"boundary\" \"=-=-=\" \"micalg\" \"pgp-sha256\" \"protocol\" \"application/pgp-signature\")"
568 << QByteArray("UID FETCH 333 \\((BODY\\.PEEK\\[(2|1|1\\.MIME)\\] ?){3}\\)");
570 QTest::newRow("encrypted")
572 << QByteArray("UID FETCH 333 \\((BODY\\.PEEK\\[(1|2)\\] ?){2}\\)");
575 QTEST_GUILESS_MAIN(CryptographyPGPTest
)