Merge "Crypto: gracefully handle unavailable data"
[trojita.git] / tests / Cryptography / test_Cryptography_PGP.cpp
blob2d33a4d3f619afd77f8d9e0a203e9a2f611b330b
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"
36 # endif
37 #endif
39 /* TODO: test cases:
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
47 * * nested scenarios
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"));
82 cEmpty();
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>());
88 # endif
89 #endif
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)));
107 int i = 0;
108 while (data.isValid() && data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet).toBool() && i++ < 1000) {
109 QTest::qWait(10);
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();
122 if (successful) {
123 QCOMPARE(qcaErrorSpy.empty(), successful);
124 QCOMPARE(qcaSuccessSpy.empty(), !successful);
127 QVERIFY(data.data(Imap::Mailbox::RoleIsFetched).toBool());
129 cEmpty();
130 QVERIFY(errorSpy->empty());
131 #else
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"));
137 cEmpty();
139 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
140 #endif
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")
153 << bsEncrypted
154 << encValid
155 << QByteArray("plaintext")
156 << QStringLiteral("valid@test.trojita.flaska.net")
157 << true;
159 // corrupted daya
160 QTest::newRow("invalid")
161 << bsEncrypted
162 << encInvalid
163 << QByteArray("plaintext")
164 << QStringLiteral("valid@test.trojita.flaska.net")
165 << false;
167 // the key used for encryption is expired
168 QTest::newRow("expiredKey")
169 << bsEncrypted
170 << encExpired
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")
174 << true;
176 // we don't have any key which is needed for encryption
177 QTest::newRow("unknownKey")
178 << bsEncrypted
179 << encUnknown
180 << QByteArray("plaintext")
181 << QStringLiteral("valid@test.trojita.flaska.net")
182 << false;
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
205 cEmpty();
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)));
223 int i = 0;
224 while (data.isValid() && data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet).toBool() && i++ < 1000) {
225 QTest::qWait(10);
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
236 cEmpty();
237 QVERIFY(errorSpy->empty());
238 #else
239 QSKIP("Cannot test without GpgME++ support");
240 #endif
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\")"
269 " NIL NIL NIL"))
270 + t.last("OK fetched\r\n"));
271 cEmpty();
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>());
277 # endif
278 #endif
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)));
296 int i = 0;
297 while (data.isValid() && data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet).toBool() && qcaErrorSpy.empty() && i++ < 1000) {
298 QTest::qWait(10);
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));
328 cEmpty();
329 QVERIFY(errorSpy->empty());
330 #else
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"));
336 cEmpty();
338 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
339 #endif
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")
358 << sigFromMe
359 << ptMimeHdr
360 << QByteArray("plaintext\r\n")
361 << true
362 << QStringLiteral("valid@test.trojita.flaska.net")
363 << QStringLiteral("Verified signature")
364 << QStringLiteral("Verified signature from Valid <valid@test.trojita.flaska.net> (")
365 << true
366 << true;
368 // my signature, but a different identity
369 QTest::newRow("my-signature-different-identity")
370 << sigFromMe
371 << ptMimeHdr
372 << QByteArray("plaintext\r\n")
373 << true
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> (")
377 << true
378 << false;
380 // my signature, different data
381 QTest::newRow("my-signature-different-data")
382 << sigFromMe
383 << ptMimeHdr
384 << QByteArray("I will pay you right now\r\n")
385 << true
386 << QStringLiteral("valid@test.trojita.flaska.net")
387 << QStringLiteral("Bad signature")
388 << QStringLiteral("Bad signature by Valid <valid@test.trojita.flaska.net> (")
389 << false
390 << false;
392 // A missing Content-Type header (and also an invalid signature)
393 QTest::newRow("invalid-implicit-content-type")
394 << sigFromMe
395 << QByteArrayLiteral("Content-Transfer-Encoding: 8bit\r\n\r\n")
396 << QByteArray("plaintext\r\n")
397 << true
398 << QStringLiteral("valid@test.trojita.flaska.net")
399 << QStringLiteral("Bad signature")
400 << QStringLiteral("Bad signature by Valid <valid@test.trojita.flaska.net> (")
401 << false
402 << false;
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"));
424 cEmpty();
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>());
430 # endif
431 #endif
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);
444 cEmpty();
445 QVERIFY(errorSpy->empty());
446 #else
447 QCOMPARE(msgModel.rowCount(data), rowCount);
448 QCOMPARE(data.data(Imap::Mailbox::RoleIsFetched).toBool(), true);
450 cEmpty();
452 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
453 #endif
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
466 << 2
467 << QString()
468 << QString();
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\")"
474 " NIL NIL NIL")
475 << 1
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"));
499 cEmpty();
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>());
505 # endif
506 #endif
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)));
526 int i = 0;
527 while (data.isValid() && data.data(Imap::Mailbox::RolePartCryptoNotFinishedYet).toBool() && qcaErrorSpy.empty() && i++ < 1000) {
528 QTest::qWait(10);
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
546 //cEmpty();
548 QVERIFY(errorSpy->empty());
549 #else
550 QCOMPARE(msgModel.rowCount(data), 2);
551 QCOMPARE(data.data(Imap::Mailbox::RoleIsFetched).toBool(), true);
552 cEmpty();
554 QSKIP("Some tests were skipped because this build doesn't have GpgME++ support");
555 #endif
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\")"
567 " NIL NIL NIL")
568 << QByteArray("UID FETCH 333 \\((BODY\\.PEEK\\[(2|1|1\\.MIME)\\] ?){3}\\)");
570 QTest::newRow("encrypted")
571 << bsEncrypted
572 << QByteArray("UID FETCH 333 \\((BODY\\.PEEK\\[(1|2)\\] ?){2}\\)");
575 QTEST_GUILESS_MAIN(CryptographyPGPTest)