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 signature of modified text
42 * * verify signature with expired key
43 * * verify signature with not yet valid key
44 * * verify signature with unknown key
48 void CryptographyPGPTest::initTestCase()
50 LibMailboxSync::initTestCase();
51 if (!qputenv("GNUPGHOME", QByteArray(QCoreApplication::applicationDirPath().toUtf8() + "/keys").constData())) {
52 QFAIL("Unable to set GNUPGHOME environment variable");
56 void CryptographyPGPTest::testDecryption()
58 QFETCH(QByteArray
, bodystructure
);
59 QFETCH(QByteArray
, cyphertext
);
60 QFETCH(QByteArray
, plaintext
);
61 QFETCH(QString
, from
);
62 QFETCH(bool, successful
);
64 // By default, there's a 50ms delay between the time we request a part download and the time it actually happens.
65 // That's too long for a unit test.
66 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
68 helperSyncBNoMessages();
69 cServer("* 1 EXISTS\r\n");
70 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
71 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
73 QCOMPARE(model
->rowCount(msgListB
), 1);
74 QModelIndex msg
= msgListB
.child(0, 0);
75 QVERIFY(msg
.isValid());
76 QCOMPARE(model
->rowCount(msg
), 0);
77 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
78 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), from
, bodystructure
)
79 + t
.last("OK fetched\r\n"));
81 QVERIFY(model
->rowCount(msg
) > 0);
82 Cryptography::MessageModel
msgModel(0, msg
);
83 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
84 # ifdef TROJITA_HAVE_GPGMEPP
85 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
88 QModelIndex mappedMsg
= msgModel
.index(0,0);
89 QVERIFY(mappedMsg
.isValid());
90 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
92 QModelIndex data
= mappedMsg
.child(0, 0);
93 QVERIFY(data
.isValid());
94 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
95 QCOMPARE(msgModel
.rowCount(data
), 0);
96 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
98 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[2\\] BODY\\.PEEK\\[1\\]|BODY.PEEK\\[1\\] BODY\\.PEEK\\[2\\])\\)"));
99 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(cyphertext
) + " BODY[1] " + asLiteral("Version: 1\r\n") + ")\r\n"
100 + t
.last("OK fetched"));
102 QSignalSpy
qcaSuccessSpy(&msgModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)));
103 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
106 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && i
++ < 1000) {
109 // allow for event processing, so that the model can retrieve the results
110 QCoreApplication::processEvents();
111 QVERIFY(!data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool());
113 if (!qcaErrorSpy
.isEmpty() && successful
) {
114 qDebug() << "Unexpected failure in crypto";
115 for (int i
= 0; i
< qcaErrorSpy
.size(); ++i
) {
116 qDebug() << qcaErrorSpy
[i
][1].toString();
117 qDebug() << qcaErrorSpy
[i
][2].toString();
122 QCOMPARE(qcaErrorSpy
.empty(), successful
);
123 QCOMPARE(qcaSuccessSpy
.empty(), !successful
);
126 QVERIFY(data
.data(Imap::Mailbox::RoleIsFetched
).toBool());
129 QVERIFY(errorSpy
->empty());
131 QCOMPARE(msgModel
.rowCount(data
), 2);
132 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), true);
134 QCOMPARE(data
.child(0, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/pgp-encrypted"));
135 QCOMPARE(data
.child(1, 0).data(Imap::Mailbox::RolePartMimeType
).toString(), QLatin1String("application/octet-stream"));
138 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
142 void CryptographyPGPTest::testDecryption_data()
144 QTest::addColumn
<QByteArray
>("bodystructure");
145 QTest::addColumn
<QByteArray
>("cyphertext");
146 QTest::addColumn
<QByteArray
>("plaintext");
147 QTest::addColumn
<QString
>("from");
148 QTest::addColumn
<bool>("successful");
150 // everything is correct
151 QTest::newRow("valid")
154 << QByteArray("plaintext")
155 << QStringLiteral("valid@test.trojita.flaska.net")
159 QTest::newRow("invalid")
162 << QByteArray("plaintext")
163 << QStringLiteral("valid@test.trojita.flaska.net")
166 // the key used for encryption is expired
167 QTest::newRow("expiredKey")
170 << QByteArray("plaintext")
171 // NOTE (jkt): This is how my QCA/2.1.0.3, GnuPG/2.0.28 behaves.
172 << QStringLiteral("valid@test.trojita.flaska.net")
175 // we don't have any key which is needed for encryption
176 QTest::newRow("unknownKey")
179 << QByteArray("plaintext")
180 << QStringLiteral("valid@test.trojita.flaska.net")
184 /** @short What happens when ENVELOPE doesn't arrive at the time that parts are already there? */
185 void CryptographyPGPTest::testDecryptWithoutEnvelope()
187 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
188 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
190 helperSyncBNoMessages();
191 cServer("* 1 EXISTS\r\n");
192 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
193 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
194 QCOMPARE(model
->rowCount(msgListB
), 1);
195 QModelIndex msg
= msgListB
.child(0, 0);
196 QVERIFY(msg
.isValid());
197 Cryptography::MessageModel
msgModel(0, msg
);
198 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
200 QCOMPARE(model
->rowCount(msg
), 0);
201 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
202 cServer("* 1 FETCH (UID 333 BODYSTRUCTURE (" + bsEncrypted
+ "))\r\n" + t
.last("OK fetched\r\n"));
203 // notice that the ENVELOPE never arrived
205 QVERIFY(model
->rowCount(msg
) > 0);
206 QModelIndex mappedMsg
= msgModel
.index(0,0);
207 QVERIFY(mappedMsg
.isValid());
208 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
210 QModelIndex data
= mappedMsg
.child(0, 0);
211 QVERIFY(data
.isValid());
212 QCOMPARE(msgModel
.rowCount(data
), 0);
213 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
215 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[2\\] BODY\\.PEEK\\[1\\]|BODY.PEEK\\[1\\] BODY\\.PEEK\\[2\\])\\)"));
216 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(encValid
) + " BODY[1] " + asLiteral("Version: 1\r\n") + ")\r\n"
217 + t
.last("OK fetched"));
219 QSignalSpy
qcaSuccessSpy(&msgModel
, SIGNAL(rowsInserted(const QModelIndex
&,int,int)));
220 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
223 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && i
++ < 1000) {
226 // allow for event processing, so that the model can retrieve the results
227 QCoreApplication::processEvents();
228 QVERIFY(!data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool());
230 QVERIFY(qcaSuccessSpy
.isEmpty());
231 QVERIFY(qcaErrorSpy
.isEmpty());
233 QVERIFY(!data
.data(Imap::Mailbox::RoleIsFetched
).toBool()); // because the ENVELOPE hasn't arrived yet
236 QVERIFY(errorSpy
->empty());
238 QSKIP("Cannot test without GpgME++ support");
242 void CryptographyPGPTest::testVerification()
244 QFETCH(QByteArray
, signature
);
245 QFETCH(QByteArray
, ptMimeHdr
);
246 QFETCH(QByteArray
, plaintext
);
247 QFETCH(bool, successful
);
248 QFETCH(QString
, from
);
249 QFETCH(QString
, tldr
);
250 QFETCH(QString
, longDesc
);
251 QFETCH(bool, validDisregardingTrust
);
252 QFETCH(bool, validCompletely
);
254 model
->setProperty("trojita-imap-delayed-fetch-part", 0);
255 helperSyncBNoMessages();
256 cServer("* 1 EXISTS\r\n");
257 cClient(t
.mk("UID FETCH 1:* (FLAGS)\r\n"));
258 cServer("* 1 FETCH (UID 333 FLAGS ())\r\n" + t
.last("OK fetched\r\n"));
259 QCOMPARE(model
->rowCount(msgListB
), 1);
260 QModelIndex msg
= msgListB
.child(0, 0);
261 QVERIFY(msg
.isValid());
262 QCOMPARE(model
->rowCount(msg
), 0);
263 cClient(t
.mk("UID FETCH 333 (" FETCH_METADATA_ITEMS
")\r\n"));
264 cServer(helperCreateTrivialEnvelope(1, 333, QStringLiteral("subj"), from
, QStringLiteral(
265 "(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 423 14 NIL NIL NIL NIL)"
266 "(\"application\" \"pgp-signature\" NIL NIL NIL \"7bit\" 851 NIL NIL NIL NIL)"
267 " \"signed\" (\"boundary\" \"=-=-=\" \"micalg\" \"pgp-sha256\" \"protocol\" \"application/pgp-signature\")"
269 + t
.last("OK fetched\r\n"));
271 QVERIFY(model
->rowCount(msg
) > 0);
272 Cryptography::MessageModel
msgModel(0, msg
);
273 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
274 # ifdef TROJITA_HAVE_GPGMEPP
275 msgModel
.registerPartHandler(std::make_shared
<Cryptography::GpgMeReplacer
>());
278 QModelIndex mappedMsg
= msgModel
.index(0,0);
279 QVERIFY(mappedMsg
.isValid());
280 QVERIFY(msgModel
.rowCount(mappedMsg
) > 0);
282 QModelIndex data
= mappedMsg
.child(0, 0);
283 QVERIFY(data
.isValid());
284 #ifdef TROJITA_HAVE_CRYPTO_MESSAGES
285 QCOMPARE(msgModel
.rowCount(data
), 0);
286 QCOMPARE(data
.data(Imap::Mailbox::RoleIsFetched
).toBool(), false);
288 cClientRegExp(t
.mk("UID FETCH 333 \\((BODY\\.PEEK\\[(2|1|1\\.MIME)\\] ?){3}\\)"));
289 cServer("* 1 FETCH (UID 333 BODY[2] " + asLiteral(signature
) + " BODY[1] " + asLiteral(plaintext
)
290 + " BODY[1.MIME] " + asLiteral(ptMimeHdr
) + ")\r\n"
291 + t
.last("OK fetched"));
293 QSignalSpy
qcaErrorSpy(&msgModel
, SIGNAL(error(const QModelIndex
&,QString
,QString
)));
296 while (data
.isValid() && data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool() && qcaErrorSpy
.empty() && i
++ < 1000) {
299 // allow for event processing, so that the model can retrieve the results
300 QCoreApplication::processEvents();
301 QVERIFY(!data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool());
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();
532 QVERIFY(!data
.data(Imap::Mailbox::RolePartCryptoNotFinishedYet
).toBool());
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
)