MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 94.0% 236 / 0 / 251
Functions: 100.0% 27 / 0 / 27
Branches: 82.6% 381 / 0 / 461

data/MailOutboxStore.cpp
Line Branch Exec Source
1 #include "MailOutboxStore.h"
2
3 #include <QDir>
4 #include <QFile>
5 #include <QJsonArray>
6 #include <QJsonDocument>
7 #include <QSaveFile>
8 #include <QSqlError>
9 #include <QSqlQuery>
10 #include <QTimeZone>
11 #include <QUuid>
12 #include <QVariant>
13
14 namespace {
15
16 105 QString joinList(const QStringList &values) {
17
4/4
✓ Branch 2 → 3 taken 105 times.
✓ Branch 3 → 4 taken 105 times.
✓ Branch 4 → 5 taken 105 times.
✓ Branch 5 → 6 taken 105 times.
105 return QString::fromUtf8(QJsonDocument(QJsonArray::fromStringList(values)).toJson(QJsonDocument::Compact));
18 }
19
20 1110 QStringList splitList(const QString &json) {
21
2/2
✓ Branch 2 → 3 taken 1110 times.
✓ Branch 3 → 4 taken 1110 times.
1110 const QJsonDocument document = QJsonDocument::fromJson(json.toUtf8());
22 1110 QStringList values;
23
8/8
✓ Branch 5 → 6 taken 1110 times.
✓ Branch 6 → 7 taken 1110 times.
✓ Branch 7 → 8 taken 1110 times.
✓ Branch 10 → 11 taken 748 times.
✓ Branch 11 → 12 taken 748 times.
✓ Branch 12 → 13 taken 748 times.
✓ Branch 17 → 9 taken 748 times.
✓ Branch 17 → 18 taken 1110 times.
1858 for (const QJsonValue &value : document.array()) values.append(value.toString());
24 1110 return values;
25 1110 }
26
27
2/2
✓ Branch 3 → 4 taken 191 times.
✓ Branch 3 → 6 taken 11 times.
202 qint64 toSeconds(const QDateTime &value) { return value.isValid() ? value.toSecsSinceEpoch() : 0; }
28 1110 QDateTime fromSeconds(qint64 value) {
29
5/7
✓ Branch 2 → 3 taken 668 times.
✓ Branch 2 → 5 taken 442 times.
✓ Branch 4 → 6 taken 668 times.
✓ Branch 7 → 8 taken 668 times.
✓ Branch 7 → 9 taken 442 times.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
2220 return value > 0 ? QDateTime::fromSecsSinceEpoch(value, QTimeZone::UTC) : QDateTime();
30 }
31
32 const char *Columns =
33 "id, account_id, identity_id, state, due, created, sent_at, attempts, error_class, last_error, message_id, "
34 "envelope_from, recipients, refused, mime_path, draft_session, summary_to, subject, reply_reference, invitation, "
35 "sent_folder_account, bcc, copy_pending";
36
37 } // namespace
38
39 831 MailOutboxStore::MailOutboxStore(QString profileDirectory)
40 831 : m_profileDirectory(std::move(profileDirectory)),
41
3/3
✓ Branch 4 → 5 taken 831 times.
✓ Branch 5 → 6 taken 831 times.
✓ Branch 9 → 10 taken 831 times.
1662 m_connectionName(QStringLiteral("mailjd-outbox-") + QUuid::createUuid().toString(QUuid::Id128)) {}
42
43 831 MailOutboxStore::~MailOutboxStore() {
44 {
45 831 QSqlDatabase db = QSqlDatabase::database(m_connectionName, false);
46
1/2
✓ Branch 4 → 5 taken 831 times.
✗ Branch 4 → 6 not taken.
831 if (db.isValid()) db.close();
47 831 }
48 831 QSqlDatabase::removeDatabase(m_connectionName);
49 831 }
50
51 832 QString MailOutboxStore::pathFor(const QString &profileDirectory) {
52
2/2
✓ Branch 2 → 3 taken 832 times.
✓ Branch 6 → 7 taken 832 times.
1664 return QDir(profileDirectory).filePath(QStringLiteral("outbox.sqlite"));
53 }
54
55 16690 QSqlDatabase MailOutboxStore::database() const { return QSqlDatabase::database(m_connectionName, false); }
56
57
8/16
✓ Branch 2 → 3 taken 5544 times.
✓ Branch 3 → 4 taken 5544 times.
✓ Branch 4 → 5 taken 5544 times.
✗ Branch 4 → 9 not taken.
✓ Branch 5 → 6 taken 5544 times.
✓ Branch 6 → 7 taken 5544 times.
✓ Branch 7 → 8 taken 5544 times.
✗ Branch 7 → 9 not taken.
✓ Branch 11 → 12 taken 5544 times.
✗ Branch 11 → 13 not taken.
✓ Branch 13 → 14 taken 5544 times.
✗ Branch 13 → 15 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
5544 bool MailOutboxStore::isOpen() const { return database().isValid() && database().isOpen(); }
58
59 90 QString MailOutboxStore::mimePath(qint64 id) const {
60
3/3
✓ Branch 2 → 3 taken 90 times.
✓ Branch 7 → 8 taken 90 times.
✓ Branch 8 → 9 taken 90 times.
270 return QDir(m_profileDirectory).filePath(QStringLiteral("outbox/%1.eml").arg(id));
61 }
62
63 831 bool MailOutboxStore::open(QString *error) {
64
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 13 taken 831 times.
831 if (m_profileDirectory.isEmpty()) {
65 ✗ if (error) *error = QStringLiteral("no profile");
66 ✗ return false;
67 }
68
2/2
✓ Branch 14 → 15 taken 831 times.
✓ Branch 15 → 16 taken 831 times.
831 QDir().mkpath(m_profileDirectory);
69
1/1
✓ Branch 18 → 19 taken 831 times.
831 const QString path = pathFor(m_profileDirectory);
70
1/1
✓ Branch 22 → 23 taken 831 times.
1662 QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName);
71
1/1
✓ Branch 25 → 26 taken 831 times.
831 db.setDatabaseName(path);
72
2/3
✓ Branch 26 → 27 taken 831 times.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 36 taken 831 times.
831 if (!db.open()) {
73 ✗ if (error) *error = db.lastError().text();
74 ✗ return false;
75 }
76
1/1
✓ Branch 37 → 38 taken 831 times.
831 QFile::setPermissions(path, QFile::ReadOwner | QFile::WriteOwner);
77
1/1
✓ Branch 38 → 39 taken 831 times.
831 QSqlQuery query(db);
78
1/1
✓ Branch 42 → 43 taken 831 times.
831 query.exec(QStringLiteral("PRAGMA journal_mode=WAL"));
79
1/1
✓ Branch 48 → 49 taken 831 times.
831 query.exec(QStringLiteral("PRAGMA synchronous=FULL"));
80
1/1
✓ Branch 54 → 55 taken 831 times.
831 const bool created = query.exec(QStringLiteral(
81 "CREATE TABLE IF NOT EXISTS outbox ("
82 "id INTEGER PRIMARY KEY AUTOINCREMENT, account_id TEXT NOT NULL, identity_id TEXT, state TEXT NOT NULL, "
83 "due INTEGER NOT NULL DEFAULT 0, created INTEGER NOT NULL, sent_at INTEGER NOT NULL DEFAULT 0, "
84 "attempts INTEGER NOT NULL DEFAULT 0, error_class TEXT, last_error TEXT, message_id TEXT, envelope_from TEXT, "
85 "recipients TEXT, refused TEXT, mime BLOB, mime_path TEXT, draft_session TEXT, summary_to TEXT, subject TEXT, "
86 "reply_reference TEXT, invitation INTEGER NOT NULL DEFAULT 0, sent_folder_account TEXT, bcc TEXT, "
87 "copy_pending INTEGER NOT NULL DEFAULT 0)"));
88
1/2
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 66 taken 831 times.
831 if (!created) {
89 ✗ if (error) *error = query.lastError().text();
90 ✗ return false;
91 }
92
2/2
✓ Branch 66 → 67 taken 831 times.
✓ Branch 70 → 71 taken 831 times.
1662 QDir(m_profileDirectory).mkpath(QStringLiteral("outbox"));
93
3/3
✓ Branch 76 → 77 taken 831 times.
✓ Branch 80 → 81 taken 831 times.
✓ Branch 81 → 82 taken 831 times.
1662 QFile::setPermissions(QDir(m_profileDirectory).filePath(QStringLiteral("outbox")),
94 831 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
95 831 return true;
96 831 }
97
98 59 bool MailOutboxStore::storeMime(qint64 id, const QByteArray &mime) {
99
2/2
✓ Branch 2 → 3 taken 59 times.
✓ Branch 3 → 4 taken 59 times.
59 QSqlQuery query(database());
100
2/2
✓ Branch 6 → 7 taken 54 times.
✓ Branch 6 → 26 taken 5 times.
59 if (mime.size() <= InlineMimeBytes) {
101
1/1
✓ Branch 10 → 11 taken 54 times.
54 query.prepare(QStringLiteral("UPDATE outbox SET mime = ?, mime_path = NULL WHERE id = ?"));
102
1/1
✓ Branch 15 → 16 taken 54 times.
54 query.addBindValue(mime);
103
1/1
✓ Branch 19 → 20 taken 54 times.
54 query.addBindValue(id);
104
2/2
✓ Branch 21 → 22 taken 54 times.
✓ Branch 22 → 23 taken 54 times.
54 QFile::remove(mimePath(id));
105
1/1
✓ Branch 24 → 25 taken 54 times.
54 return query.exec();
106 }
107
2/2
✓ Branch 26 → 27 taken 5 times.
✓ Branch 27 → 28 taken 5 times.
5 QSaveFile file(mimePath(id));
108
4/6
✓ Branch 30 → 31 taken 5 times.
✓ Branch 33 → 34 taken 5 times.
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 40 not taken.
✓ Branch 37 → 38 taken 5 times.
✗ Branch 37 → 40 not taken.
15 if (!file.open(QIODevice::WriteOnly) || !file.setPermissions(QFile::ReadOwner | QFile::WriteOwner) ||
109
5/8
✓ Branch 31 → 32 taken 5 times.
✗ Branch 31 → 40 not taken.
✓ Branch 35 → 36 taken 5 times.
✓ Branch 38 → 39 taken 5 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 5 times.
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 5 times.
15 file.write(mime) != mime.size() || !file.commit())
110 ✗ return false;
111
1/1
✓ Branch 47 → 48 taken 5 times.
5 query.prepare(QStringLiteral("UPDATE outbox SET mime = NULL, mime_path = ? WHERE id = ?"));
112
2/2
✓ Branch 55 → 56 taken 5 times.
✓ Branch 57 → 58 taken 5 times.
10 query.addBindValue(QStringLiteral("outbox/%1.eml").arg(id));
113
1/1
✓ Branch 64 → 65 taken 5 times.
5 query.addBindValue(id);
114
1/1
✓ Branch 66 → 67 taken 5 times.
5 return query.exec();
115 59 }
116
117 128 QByteArray MailOutboxStore::loadMime(qint64 id, const QString &path, const QByteArray &inlineBytes) const {
118
2/2
✓ Branch 3 → 4 taken 111 times.
✓ Branch 3 → 5 taken 17 times.
128 if (path.isEmpty()) return inlineBytes;
119
2/2
✓ Branch 5 → 6 taken 17 times.
✓ Branch 6 → 7 taken 17 times.
17 QFile file(mimePath(id));
120
5/8
✓ Branch 9 → 10 taken 17 times.
✓ Branch 10 → 11 taken 17 times.
✗ Branch 10 → 13 not taken.
✓ Branch 11 → 12 taken 17 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 17 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 17 times.
17 if (!file.open(QIODevice::ReadOnly) || file.size() > MaxMimeBytes) return {};
121
1/1
✓ Branch 17 → 18 taken 17 times.
17 return file.readAll();
122 17 }
123
124 51 qint64 MailOutboxStore::enqueue(const OutboxEntry &entry) {
125
7/9
✓ Branch 2 → 3 taken 51 times.
✓ Branch 3 → 4 taken 51 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 50 times.
✓ Branch 5 → 8 taken 1 time.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 50 times.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 50 times.
51 if (!isOpen() || entry.mime.isEmpty() || entry.mime.size() > MaxMimeBytes) return 0;
126
1/1
✓ Branch 12 → 13 taken 50 times.
50 QSqlDatabase db = database();
127
1/1
✓ Branch 13 → 14 taken 50 times.
50 db.transaction();
128
1/1
✓ Branch 14 → 15 taken 50 times.
50 QSqlQuery query(db);
129
1/1
✓ Branch 18 → 19 taken 50 times.
50 query.prepare(QStringLiteral(
130 "INSERT INTO outbox (account_id, identity_id, state, due, created, attempts, message_id, envelope_from, "
131 "recipients, refused, draft_session, summary_to, subject, reply_reference, invitation, sent_folder_account, bcc) "
132 "VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, '[]', ?, ?, ?, ?, ?, ?, ?)"));
133
1/1
✓ Branch 23 → 24 taken 50 times.
50 query.addBindValue(entry.accountId);
134
1/1
✓ Branch 27 → 28 taken 50 times.
50 query.addBindValue(entry.identityId);
135
5/7
✓ Branch 31 → 32 taken 3 times.
✓ Branch 31 → 35 taken 47 times.
✓ Branch 37 → 38 taken 50 times.
✓ Branch 40 → 41 taken 3 times.
✓ Branch 40 → 42 taken 47 times.
✗ Branch 146 → 147 not taken.
✗ Branch 146 → 148 not taken.
53 query.addBindValue(entry.state.isEmpty() ? QStringLiteral("undo") : entry.state);
136
2/2
✓ Branch 43 → 44 taken 50 times.
✓ Branch 45 → 46 taken 50 times.
50 query.addBindValue(toSeconds(entry.due));
137
5/6
✓ Branch 48 → 49 taken 50 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 50 times.
✓ Branch 51 → 52 taken 50 times.
✓ Branch 52 → 53 taken 50 times.
✓ Branch 54 → 55 taken 50 times.
50 query.addBindValue(toSeconds(entry.created.isValid() ? entry.created : QDateTime::currentDateTimeUtc()));
138
1/1
✓ Branch 59 → 60 taken 50 times.
50 query.addBindValue(entry.messageId);
139
1/1
✓ Branch 63 → 64 taken 50 times.
50 query.addBindValue(entry.envelopeFrom);
140
2/2
✓ Branch 66 → 67 taken 50 times.
✓ Branch 68 → 69 taken 50 times.
50 query.addBindValue(joinList(entry.recipients));
141
1/1
✓ Branch 73 → 74 taken 50 times.
50 query.addBindValue(entry.draftSession);
142
1/1
✓ Branch 77 → 78 taken 50 times.
50 query.addBindValue(entry.summaryTo);
143
1/1
✓ Branch 81 → 82 taken 50 times.
50 query.addBindValue(entry.subject);
144
1/1
✓ Branch 85 → 86 taken 50 times.
50 query.addBindValue(entry.replyReference);
145
3/3
✓ Branch 88 → 89 taken 3 times.
✓ Branch 88 → 90 taken 47 times.
✓ Branch 92 → 93 taken 50 times.
50 query.addBindValue(entry.invitation ? 1 : 0);
146
3/3
✓ Branch 96 → 97 taken 43 times.
✓ Branch 96 → 98 taken 7 times.
✓ Branch 100 → 101 taken 50 times.
50 query.addBindValue(entry.sentFolderAccount.isEmpty() ? entry.accountId : entry.sentFolderAccount);
147
2/2
✓ Branch 103 → 104 taken 50 times.
✓ Branch 105 → 106 taken 50 times.
50 query.addBindValue(joinList(entry.bcc));
148
2/3
✓ Branch 108 → 109 taken 50 times.
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 112 taken 50 times.
50 if (!query.exec()) {
149 ✗ db.rollback();
150 ✗ return 0;
151 }
152
2/2
✓ Branch 112 → 113 taken 50 times.
✓ Branch 113 → 114 taken 50 times.
50 const qint64 id = query.lastInsertId().toLongLong();
153
2/3
✓ Branch 115 → 116 taken 50 times.
✗ Branch 116 → 117 not taken.
✓ Branch 116 → 119 taken 50 times.
50 if (!storeMime(id, entry.mime)) {
154 ✗ db.rollback();
155 ✗ return 0;
156 }
157
2/3
✓ Branch 119 → 120 taken 50 times.
✓ Branch 120 → 121 taken 50 times.
✗ Branch 120 → 122 not taken.
50 return db.commit() ? id : 0;
158 50 }
159
160 namespace {
161 370 OutboxEntry entryFrom(const QSqlQuery &query) {
162 370 OutboxEntry entry;
163
2/2
✓ Branch 3 → 4 taken 370 times.
✓ Branch 4 → 5 taken 370 times.
370 entry.id = query.value(0).toLongLong();
164
2/2
✓ Branch 6 → 7 taken 370 times.
✓ Branch 7 → 8 taken 370 times.
370 entry.accountId = query.value(1).toString();
165
2/2
✓ Branch 11 → 12 taken 370 times.
✓ Branch 12 → 13 taken 370 times.
370 entry.identityId = query.value(2).toString();
166
2/2
✓ Branch 16 → 17 taken 370 times.
✓ Branch 17 → 18 taken 370 times.
370 entry.state = query.value(3).toString();
167
3/3
✓ Branch 21 → 22 taken 370 times.
✓ Branch 22 → 23 taken 370 times.
✓ Branch 23 → 24 taken 370 times.
370 entry.due = fromSeconds(query.value(4).toLongLong());
168
3/3
✓ Branch 27 → 28 taken 370 times.
✓ Branch 28 → 29 taken 370 times.
✓ Branch 29 → 30 taken 370 times.
370 entry.created = fromSeconds(query.value(5).toLongLong());
169
3/3
✓ Branch 33 → 34 taken 370 times.
✓ Branch 34 → 35 taken 370 times.
✓ Branch 35 → 36 taken 370 times.
370 entry.sentAt = fromSeconds(query.value(6).toLongLong());
170
2/2
✓ Branch 39 → 40 taken 370 times.
✓ Branch 40 → 41 taken 370 times.
370 entry.attempts = query.value(7).toInt();
171
2/2
✓ Branch 42 → 43 taken 370 times.
✓ Branch 43 → 44 taken 370 times.
370 entry.errorClass = query.value(8).toString();
172
2/2
✓ Branch 47 → 48 taken 370 times.
✓ Branch 48 → 49 taken 370 times.
370 entry.lastError = query.value(9).toString();
173
2/2
✓ Branch 52 → 53 taken 370 times.
✓ Branch 53 → 54 taken 370 times.
370 entry.messageId = query.value(10).toString();
174
2/2
✓ Branch 57 → 58 taken 370 times.
✓ Branch 58 → 59 taken 370 times.
370 entry.envelopeFrom = query.value(11).toString();
175
3/3
✓ Branch 62 → 63 taken 370 times.
✓ Branch 63 → 64 taken 370 times.
✓ Branch 64 → 65 taken 370 times.
370 entry.recipients = splitList(query.value(12).toString());
176
3/3
✓ Branch 69 → 70 taken 370 times.
✓ Branch 70 → 71 taken 370 times.
✓ Branch 71 → 72 taken 370 times.
370 entry.refused = splitList(query.value(13).toString());
177
2/2
✓ Branch 76 → 77 taken 370 times.
✓ Branch 77 → 78 taken 370 times.
370 entry.draftSession = query.value(15).toString();
178
2/2
✓ Branch 81 → 82 taken 370 times.
✓ Branch 82 → 83 taken 370 times.
370 entry.summaryTo = query.value(16).toString();
179
2/2
✓ Branch 86 → 87 taken 370 times.
✓ Branch 87 → 88 taken 370 times.
370 entry.subject = query.value(17).toString();
180
2/2
✓ Branch 91 → 92 taken 370 times.
✓ Branch 92 → 93 taken 370 times.
370 entry.replyReference = query.value(18).toString();
181
2/2
✓ Branch 96 → 97 taken 370 times.
✓ Branch 97 → 98 taken 370 times.
370 entry.invitation = query.value(19).toInt() != 0;
182
2/2
✓ Branch 99 → 100 taken 370 times.
✓ Branch 100 → 101 taken 370 times.
370 entry.sentFolderAccount = query.value(20).toString();
183
3/3
✓ Branch 104 → 105 taken 370 times.
✓ Branch 105 → 106 taken 370 times.
✓ Branch 106 → 107 taken 370 times.
370 entry.bcc = splitList(query.value(21).toString());
184
2/2
✓ Branch 111 → 112 taken 370 times.
✓ Branch 112 → 113 taken 370 times.
370 entry.copyPending = query.value(22).toInt() != 0;
185 370 return entry;
186 ✗ }
187 } // namespace
188
189 129 std::optional<OutboxEntry> MailOutboxStore::find(qint64 id) const {
190
2/3
✓ Branch 2 → 3 taken 129 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 129 times.
129 if (!isOpen()) return std::nullopt;
191
2/2
✓ Branch 5 → 6 taken 129 times.
✓ Branch 6 → 7 taken 129 times.
129 QSqlQuery query(database());
192
2/2
✓ Branch 13 → 14 taken 129 times.
✓ Branch 14 → 15 taken 129 times.
258 query.prepare(QStringLiteral("SELECT %1, mime FROM outbox WHERE id = ?").arg(QLatin1String(Columns)));
193
1/1
✓ Branch 20 → 21 taken 129 times.
129 query.addBindValue(id);
194
7/8
✓ Branch 22 → 23 taken 129 times.
✓ Branch 23 → 24 taken 129 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 129 times.
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 27 taken 128 times.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 30 taken 128 times.
129 if (!query.exec() || !query.next()) return std::nullopt;
195
1/1
✓ Branch 30 → 31 taken 128 times.
128 OutboxEntry entry = entryFrom(query);
196
5/5
✓ Branch 31 → 32 taken 128 times.
✓ Branch 32 → 33 taken 128 times.
✓ Branch 33 → 34 taken 128 times.
✓ Branch 34 → 35 taken 128 times.
✓ Branch 35 → 36 taken 128 times.
128 entry.mime = loadMime(id, query.value(14).toString(), query.value(23).toByteArray());
197 128 return entry;
198 129 }
199
200 1771 QList<OutboxEntry> MailOutboxStore::entries() const {
201 1771 QList<OutboxEntry> out;
202
2/3
✓ Branch 2 → 3 taken 1771 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1771 times.
1771 if (!isOpen()) return out;
203
2/2
✓ Branch 5 → 6 taken 1771 times.
✓ Branch 6 → 7 taken 1771 times.
1771 QSqlQuery query(database());
204
3/4
✓ Branch 13 → 14 taken 1771 times.
✓ Branch 14 → 15 taken 1771 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1771 times.
3542 if (!query.exec(QStringLiteral("SELECT %1 FROM outbox ORDER BY created, id").arg(QLatin1String(Columns)))) return out;
205
5/5
✓ Branch 21 → 22 taken 211 times.
✓ Branch 22 → 23 taken 211 times.
✓ Branch 25 → 26 taken 1982 times.
✓ Branch 26 → 21 taken 211 times.
✓ Branch 26 → 27 taken 1771 times.
1982 while (query.next()) out.append(entryFrom(query));
206 1771 return out;
207 1771 }
208
209 33 QList<OutboxEntry> MailOutboxStore::due(const QDateTime &now) const {
210 33 QList<OutboxEntry> out;
211
2/3
✓ Branch 2 → 3 taken 33 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 33 times.
33 if (!isOpen()) return out;
212
2/2
✓ Branch 5 → 6 taken 33 times.
✓ Branch 6 → 7 taken 33 times.
33 QSqlQuery query(database());
213
1/1
✓ Branch 14 → 15 taken 33 times.
99 query.prepare(QStringLiteral("SELECT %1 FROM outbox WHERE state IN ('undo','scheduled','queued','retry') AND due <= ? "
214
1/1
✓ Branch 13 → 14 taken 33 times.
99 "ORDER BY due, id").arg(QLatin1String(Columns)));
215
2/2
✓ Branch 19 → 20 taken 33 times.
✓ Branch 21 → 22 taken 33 times.
33 query.addBindValue(toSeconds(now));
216
2/3
✓ Branch 23 → 24 taken 33 times.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 33 times.
33 if (!query.exec()) return out;
217
5/5
✓ Branch 27 → 28 taken 28 times.
✓ Branch 28 → 29 taken 28 times.
✓ Branch 31 → 32 taken 61 times.
✓ Branch 32 → 27 taken 28 times.
✓ Branch 32 → 33 taken 33 times.
61 while (query.next()) out.append(entryFrom(query));
218 33 return out;
219 33 }
220
221 3 QList<OutboxEntry> MailOutboxStore::interrupted() const {
222 3 QList<OutboxEntry> out;
223
2/3
✓ Branch 2 → 3 taken 3 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (!isOpen()) return out;
224
2/2
✓ Branch 5 → 6 taken 3 times.
✓ Branch 6 → 7 taken 3 times.
3 QSqlQuery query(database());
225
3/4
✓ Branch 13 → 14 taken 3 times.
✓ Branch 14 → 15 taken 3 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 3 times.
6 if (!query.exec(QStringLiteral("SELECT %1 FROM outbox WHERE state = 'sending' ORDER BY id").arg(QLatin1String(Columns))))
226 ✗ return out;
227
5/5
✓ Branch 21 → 22 taken 3 times.
✓ Branch 22 → 23 taken 3 times.
✓ Branch 25 → 26 taken 6 times.
✓ Branch 26 → 21 taken 3 times.
✓ Branch 26 → 27 taken 3 times.
6 while (query.next()) out.append(entryFrom(query));
228 3 return out;
229 3 }
230
231 50 bool MailOutboxStore::setState(qint64 id, const QString &state, const QDateTime &due) {
232
2/3
✓ Branch 2 → 3 taken 50 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 50 times.
50 if (!isOpen()) return false;
233
2/2
✓ Branch 5 → 6 taken 50 times.
✓ Branch 6 → 7 taken 50 times.
50 QSqlQuery query(database());
234
3/3
✓ Branch 8 → 9 taken 50 times.
✓ Branch 9 → 10 taken 27 times.
✓ Branch 9 → 26 taken 23 times.
50 if (due.isValid()) {
235
1/1
✓ Branch 13 → 14 taken 27 times.
27 query.prepare(QStringLiteral("UPDATE outbox SET state = ?, due = ?, attempts = attempts + ? WHERE id = ?"));
236
1/1
✓ Branch 18 → 19 taken 27 times.
27 query.addBindValue(state);
237
2/2
✓ Branch 21 → 22 taken 27 times.
✓ Branch 23 → 24 taken 27 times.
27 query.addBindValue(toSeconds(due));
238 } else {
239
1/1
✓ Branch 29 → 30 taken 23 times.
23 query.prepare(QStringLiteral("UPDATE outbox SET state = ?, attempts = attempts + ? WHERE id = ?"));
240
1/1
✓ Branch 34 → 35 taken 23 times.
23 query.addBindValue(state);
241 }
242
3/3
✓ Branch 40 → 41 taken 23 times.
✓ Branch 40 → 42 taken 27 times.
✓ Branch 44 → 45 taken 50 times.
50 query.addBindValue(state == QLatin1String("sending") ? 1 : 0);
243
1/1
✓ Branch 48 → 49 taken 50 times.
50 query.addBindValue(id);
244
4/6
✓ Branch 50 → 51 taken 50 times.
✓ Branch 51 → 52 taken 50 times.
✗ Branch 51 → 55 not taken.
✓ Branch 52 → 53 taken 50 times.
✓ Branch 53 → 54 taken 50 times.
✗ Branch 53 → 55 not taken.
50 return query.exec() && query.numRowsAffected() == 1;
245 50 }
246
247 32 bool MailOutboxStore::recordFailure(qint64 id, const QString &errorClass, const QString &error, const QString &state,
248 const QDateTime &nextDue) {
249
2/3
✓ Branch 2 → 3 taken 32 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 32 times.
32 if (!isOpen()) return false;
250
2/2
✓ Branch 5 → 6 taken 32 times.
✓ Branch 6 → 7 taken 32 times.
32 QSqlQuery query(database());
251
1/1
✓ Branch 11 → 12 taken 32 times.
32 query.prepare(QStringLiteral("UPDATE outbox SET state = ?, error_class = ?, last_error = ?, due = ? WHERE id = ?"));
252
1/1
✓ Branch 16 → 17 taken 32 times.
32 query.addBindValue(state);
253
1/1
✓ Branch 20 → 21 taken 32 times.
32 query.addBindValue(errorClass);
254
2/2
✓ Branch 23 → 24 taken 32 times.
✓ Branch 25 → 26 taken 32 times.
32 query.addBindValue(error.left(2000));
255
2/2
✓ Branch 29 → 30 taken 32 times.
✓ Branch 31 → 32 taken 32 times.
32 query.addBindValue(toSeconds(nextDue));
256
1/1
✓ Branch 35 → 36 taken 32 times.
32 query.addBindValue(id);
257
4/6
✓ Branch 37 → 38 taken 32 times.
✓ Branch 38 → 39 taken 32 times.
✗ Branch 38 → 42 not taken.
✓ Branch 39 → 40 taken 32 times.
✓ Branch 40 → 41 taken 32 times.
✗ Branch 40 → 42 not taken.
32 return query.exec() && query.numRowsAffected() == 1;
258 32 }
259
260 2 bool MailOutboxStore::recordPartial(qint64 id, const QStringList &refused, const QString &error) {
261
2/3
✓ Branch 2 → 3 taken 2 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 if (!isOpen()) return false;
262
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 6 → 7 taken 2 times.
2 QSqlQuery query(database());
263
1/1
✓ Branch 11 → 12 taken 2 times.
2 query.prepare(QStringLiteral(
264 "UPDATE outbox SET state = 'failed', error_class = 'recipients', last_error = ?, refused = ?, recipients = ? "
265 "WHERE id = ?"));
266
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 17 → 18 taken 2 times.
2 query.addBindValue(error.left(2000));
267
2/2
✓ Branch 21 → 22 taken 2 times.
✓ Branch 23 → 24 taken 2 times.
2 query.addBindValue(joinList(refused));
268
2/2
✓ Branch 27 → 28 taken 2 times.
✓ Branch 29 → 30 taken 2 times.
2 query.addBindValue(joinList(refused));
269
1/1
✓ Branch 34 → 35 taken 2 times.
2 query.addBindValue(id);
270
4/6
✓ Branch 36 → 37 taken 2 times.
✓ Branch 37 → 38 taken 2 times.
✗ Branch 37 → 41 not taken.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 39 → 40 taken 2 times.
✗ Branch 39 → 41 not taken.
2 return query.exec() && query.numRowsAffected() == 1;
271 2 }
272
273 10 bool MailOutboxStore::markSent(qint64 id, const QDateTime &sentAt, const QByteArray &transmittedMime) {
274
2/3
✓ Branch 2 → 3 taken 10 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 10 times.
10 if (!isOpen()) return false;
275
1/1
✓ Branch 5 → 6 taken 10 times.
10 QSqlDatabase db = database();
276
1/1
✓ Branch 6 → 7 taken 10 times.
10 db.transaction();
277
1/1
✓ Branch 7 → 8 taken 10 times.
10 QSqlQuery query(db);
278
1/1
✓ Branch 11 → 12 taken 10 times.
10 query.prepare(QStringLiteral("UPDATE outbox SET state = 'sent', sent_at = ?, error_class = NULL, last_error = NULL "
279 "WHERE id = ?"));
280
2/2
✓ Branch 15 → 16 taken 10 times.
✓ Branch 17 → 18 taken 10 times.
10 query.addBindValue(toSeconds(sentAt));
281
1/1
✓ Branch 21 → 22 taken 10 times.
10 query.addBindValue(id);
282
9/13
✓ Branch 23 → 24 taken 10 times.
✓ Branch 24 → 25 taken 10 times.
✗ Branch 24 → 31 not taken.
✓ Branch 25 → 26 taken 10 times.
✓ Branch 26 → 27 taken 10 times.
✗ Branch 26 → 31 not taken.
✓ Branch 28 → 29 taken 9 times.
✓ Branch 28 → 32 taken 1 time.
✓ Branch 29 → 30 taken 9 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 9 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 36 taken 10 times.
10 if (!query.exec() || query.numRowsAffected() != 1 || (!transmittedMime.isEmpty() && !storeMime(id, transmittedMime))) {
283 ✗ db.rollback();
284 ✗ return false;
285 }
286
1/1
✓ Branch 36 → 37 taken 10 times.
10 return db.commit();
287 10 }
288
289 1 bool MailOutboxStore::setRecipients(qint64 id, const QStringList &recipients) {
290
2/3
✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!isOpen()) return false;
291
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
1 QSqlQuery query(database());
292
1/1
✓ Branch 11 → 12 taken 1 time.
1 query.prepare(QStringLiteral("UPDATE outbox SET recipients = ? WHERE id = ?"));
293
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
1 query.addBindValue(joinList(recipients));
294
1/1
✓ Branch 22 → 23 taken 1 time.
1 query.addBindValue(id);
295
4/6
✓ Branch 24 → 25 taken 1 time.
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 29 not taken.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 29 not taken.
1 return query.exec() && query.numRowsAffected() == 1;
296 1 }
297
298 1 bool MailOutboxStore::setCopyPending(qint64 id, bool pending) {
299
2/3
✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!isOpen()) return false;
300
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
1 QSqlQuery query(database());
301
1/1
✓ Branch 11 → 12 taken 1 time.
1 query.prepare(QStringLiteral("UPDATE outbox SET copy_pending = ? WHERE id = ?"));
302
2/3
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
✓ Branch 19 → 20 taken 1 time.
1 query.addBindValue(pending ? 1 : 0);
303
1/1
✓ Branch 23 → 24 taken 1 time.
1 query.addBindValue(id);
304
4/6
✓ Branch 25 → 26 taken 1 time.
✓ Branch 26 → 27 taken 1 time.
✗ Branch 26 → 30 not taken.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 30 not taken.
1 return query.exec() && query.numRowsAffected() == 1;
305 1 }
306
307 14 bool MailOutboxStore::remove(qint64 id) {
308
2/3
✓ Branch 2 → 3 taken 14 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 14 times.
14 if (!isOpen()) return false;
309
2/2
✓ Branch 5 → 6 taken 14 times.
✓ Branch 6 → 7 taken 14 times.
14 QSqlQuery query(database());
310
1/1
✓ Branch 11 → 12 taken 14 times.
14 query.prepare(QStringLiteral("DELETE FROM outbox WHERE id = ?"));
311
1/1
✓ Branch 16 → 17 taken 14 times.
14 query.addBindValue(id);
312
2/2
✓ Branch 18 → 19 taken 14 times.
✓ Branch 19 → 20 taken 14 times.
14 QFile::remove(mimePath(id));
313
4/6
✓ Branch 21 → 22 taken 14 times.
✓ Branch 22 → 23 taken 14 times.
✗ Branch 22 → 26 not taken.
✓ Branch 23 → 24 taken 14 times.
✓ Branch 24 → 25 taken 14 times.
✗ Branch 24 → 26 not taken.
14 return query.exec() && query.numRowsAffected() == 1;
314 14 }
315
316 3447 int MailOutboxStore::count(const QStringList &states) const {
317
2/3
✓ Branch 2 → 3 taken 3447 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3447 times.
3447 if (!isOpen()) return 0;
318
2/2
✓ Branch 5 → 6 taken 3447 times.
✓ Branch 6 → 7 taken 3447 times.
3447 QSqlQuery query(database());
319
2/2
✓ Branch 9 → 10 taken 1741 times.
✓ Branch 9 → 17 taken 1706 times.
3447 if (states.isEmpty()) {
320
1/1
✓ Branch 13 → 14 taken 1741 times.
1741 query.exec(QStringLiteral("SELECT COUNT(*) FROM outbox"));
321 } else {
322 1706 QStringList marks;
323
3/3
✓ Branch 21 → 22 taken 3411 times.
✓ Branch 26 → 18 taken 3411 times.
✓ Branch 26 → 27 taken 1706 times.
5117 for (qsizetype i = 0; i < states.size(); ++i) marks.append(QStringLiteral("?"));
324
3/3
✓ Branch 33 → 34 taken 1706 times.
✓ Branch 34 → 35 taken 1706 times.
✓ Branch 35 → 36 taken 1706 times.
3412 query.prepare(QStringLiteral("SELECT COUNT(*) FROM outbox WHERE state IN (%1)").arg(marks.join(QLatin1Char(','))));
325
3/3
✓ Branch 45 → 46 taken 3411 times.
✓ Branch 49 → 42 taken 3411 times.
✓ Branch 49 → 50 taken 1706 times.
5117 for (const QString &state : states) query.addBindValue(state);
326
1/1
✓ Branch 50 → 51 taken 1706 times.
1706 query.exec();
327 1706 }
328
5/9
✓ Branch 53 → 54 taken 3447 times.
✓ Branch 54 → 55 taken 3447 times.
✗ Branch 54 → 58 not taken.
✓ Branch 55 → 56 taken 3447 times.
✓ Branch 56 → 57 taken 3447 times.
✓ Branch 60 → 61 taken 3447 times.
✗ Branch 60 → 62 not taken.
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
3447 return query.next() ? query.value(0).toInt() : 0;
329 3447 }
330