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: 93.5% 58 / 0 / 62
Functions: 100.0% 8 / 0 / 8
Branches: 79.8% 87 / 0 / 109

data/ConflictHistory.cpp
Line Branch Exec Source
1 #include "ConflictHistory.h"
2
3 #include <QLoggingCategory>
4 #include <QSqlError>
5 #include <QSqlQuery>
6 #include <QVariant>
7
8
4/7
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 8 taken 112 times.
✓ Branch 4 → 5 taken 11 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 11 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
123 Q_LOGGING_CATEGORY(lcConflictHistory, "mailjd.conflict.history")
9
10 namespace ConflictHistory {
11
12 namespace {
13
14 const char *kColumns = "id, account, collection, uid, component, title, resolved_at, kept_side, losing_text";
15
16 194 Entry entryOf(const QSqlQuery &q) {
17 194 Entry entry;
18
2/2
✓ Branch 2 → 3 taken 194 times.
✓ Branch 3 → 4 taken 194 times.
194 entry.id = q.value(0).toLongLong();
19
2/2
✓ Branch 5 → 6 taken 194 times.
✓ Branch 6 → 7 taken 194 times.
194 entry.account = q.value(1).toString();
20
2/2
✓ Branch 10 → 11 taken 194 times.
✓ Branch 11 → 12 taken 194 times.
194 entry.collection = q.value(2).toString();
21
2/2
✓ Branch 15 → 16 taken 194 times.
✓ Branch 16 → 17 taken 194 times.
194 entry.uid = q.value(3).toString();
22
2/2
✓ Branch 20 → 21 taken 194 times.
✓ Branch 21 → 22 taken 194 times.
194 entry.component = q.value(4).toString();
23
2/2
✓ Branch 25 → 26 taken 194 times.
✓ Branch 26 → 27 taken 194 times.
194 entry.title = q.value(5).toString();
24
2/2
✓ Branch 30 → 31 taken 194 times.
✓ Branch 31 → 32 taken 194 times.
194 entry.resolvedAt = q.value(6).toLongLong();
25
2/2
✓ Branch 33 → 34 taken 194 times.
✓ Branch 34 → 35 taken 194 times.
194 entry.keptSide = q.value(7).toString();
26
2/2
✓ Branch 38 → 39 taken 194 times.
✓ Branch 39 → 40 taken 194 times.
194 entry.losingText = q.value(8).toString();
27 194 return entry;
28 ✗ }
29
30 } // namespace
31
32 426 QString createStatement() {
33 426 return QStringLiteral("CREATE TABLE IF NOT EXISTS conflict_history ("
34 " id INTEGER PRIMARY KEY AUTOINCREMENT,"
35 " account TEXT NOT NULL DEFAULT '',"
36 " collection TEXT NOT NULL DEFAULT '',"
37 " uid TEXT NOT NULL,"
38 " component TEXT NOT NULL DEFAULT '',"
39 " title TEXT NOT NULL DEFAULT '',"
40 " resolved_at INTEGER NOT NULL,"
41 " kept_side TEXT NOT NULL DEFAULT '',"
42 " losing_text TEXT NOT NULL DEFAULT '')");
43 }
44
45 123 bool add(QSqlDatabase &db, const Entry &entry, qint64 now) {
46
1/1
✓ Branch 2 → 3 taken 123 times.
123 QSqlQuery q(db);
47
1/1
✓ Branch 6 → 7 taken 123 times.
123 q.prepare(QStringLiteral("INSERT INTO conflict_history (account, collection, uid, component, title, resolved_at, "
48 "kept_side, losing_text) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"));
49 // A null QString binds as SQL NULL; the columns are NOT NULL.
50
4/4
✓ Branch 3 → 4 taken 331 times.
✓ Branch 3 → 7 taken 530 times.
✓ Branch 10 → 11 taken 331 times.
✓ Branch 10 → 12 taken 530 times.
1192 const auto text = [](const QString &value) { return QVariant(value.isNull() ? QStringLiteral("") : value); };
51 1107 for (const QVariant &value : {text(entry.account), text(entry.collection), text(entry.uid), text(entry.component),
52
9/13
✓ Branch 9 → 10 taken 123 times.
✓ Branch 10 → 11 taken 123 times.
✓ Branch 11 → 12 taken 123 times.
✓ Branch 12 → 13 taken 123 times.
✓ Branch 13 → 14 taken 123 times.
✓ Branch 15 → 16 taken 123 times.
✓ Branch 16 → 17 taken 123 times.
✓ Branch 23 → 20 taken 984 times.
✓ Branch 23 → 24 taken 123 times.
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 98 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
2214 text(entry.title), QVariant(now), text(entry.keptSide), text(entry.losingText)})
53
3/5
✓ Branch 21 → 22 taken 984 times.
✓ Branch 25 → 26 taken 984 times.
✓ Branch 25 → 29 taken 123 times.
✗ Branch 101 → 102 not taken.
✗ Branch 101 → 105 not taken.
2091 q.addBindValue(value);
54
2/3
✓ Branch 30 → 31 taken 123 times.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 48 taken 123 times.
123 if (!q.exec()) {
55 ✗ qCWarning(lcConflictHistory) << "insert failed:" << q.lastError().text();
56 ✗ return false;
57 }
58
1/1
✓ Branch 48 → 49 taken 123 times.
123 QSqlQuery prune(db);
59
1/1
✓ Branch 52 → 53 taken 123 times.
123 prune.prepare(QStringLiteral("DELETE FROM conflict_history WHERE resolved_at < ?"));
60
1/1
✓ Branch 57 → 58 taken 123 times.
123 prune.addBindValue(now - qint64(kMaxAgeDays) * 86400);
61
1/1
✓ Branch 59 → 60 taken 123 times.
123 prune.exec();
62
1/1
✓ Branch 63 → 64 taken 123 times.
123 prune.prepare(QStringLiteral("DELETE FROM conflict_history WHERE id NOT IN "
63 "(SELECT id FROM conflict_history ORDER BY resolved_at DESC, id DESC LIMIT ?)"));
64
1/1
✓ Branch 68 → 69 taken 123 times.
123 prune.addBindValue(kLimit);
65
1/1
✓ Branch 70 → 71 taken 123 times.
123 prune.exec();
66
8/8
✓ Branch 71 → 72 taken 123 times.
✓ Branch 75 → 76 taken 123 times.
✓ Branch 76 → 77 taken 123 times.
✓ Branch 77 → 78 taken 123 times.
✓ Branch 78 → 79 taken 123 times.
✓ Branch 79 → 80 taken 123 times.
✓ Branch 83 → 73 taken 123 times.
✓ Branch 83 → 84 taken 123 times.
246 qCInfo(lcConflictHistory) << "kept the replaced version of a" << entry.component << "resolved as" << entry.keptSide;
67 123 return true;
68 123 }
69
70 1789 QList<Entry> list(const QSqlDatabase &db, int limit) {
71 1789 QList<Entry> entries;
72
1/1
✓ Branch 2 → 3 taken 1789 times.
1789 QSqlQuery q(db);
73
1/1
✓ Branch 9 → 10 taken 1789 times.
5367 q.prepare(QStringLiteral("SELECT %1 FROM conflict_history ORDER BY resolved_at DESC, id DESC LIMIT ?")
74
1/1
✓ Branch 8 → 9 taken 1789 times.
5367 .arg(QLatin1String(kColumns)));
75
1/1
✓ Branch 15 → 16 taken 1789 times.
1789 q.addBindValue(limit);
76
2/3
✓ Branch 17 → 18 taken 1789 times.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 1789 times.
1789 if (!q.exec())
77 ✗ return entries;
78
3/3
✓ Branch 25 → 26 taken 1978 times.
✓ Branch 26 → 21 taken 189 times.
✓ Branch 26 → 27 taken 1789 times.
1978 while (q.next())
79
2/2
✓ Branch 21 → 22 taken 189 times.
✓ Branch 22 → 23 taken 189 times.
189 entries.append(entryOf(q));
80 1789 return entries;
81 1789 }
82
83 7 std::optional<Entry> find(const QSqlDatabase &db, qint64 id) {
84
1/1
✓ Branch 2 → 3 taken 7 times.
7 QSqlQuery q(db);
85
2/2
✓ Branch 8 → 9 taken 7 times.
✓ Branch 9 → 10 taken 7 times.
14 q.prepare(QStringLiteral("SELECT %1 FROM conflict_history WHERE id = ?").arg(QLatin1String(kColumns)));
86
1/1
✓ Branch 15 → 16 taken 7 times.
7 q.addBindValue(id);
87
7/8
✓ Branch 17 → 18 taken 7 times.
✓ Branch 18 → 19 taken 7 times.
✗ Branch 18 → 22 not taken.
✓ Branch 19 → 20 taken 7 times.
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 22 taken 2 times.
✓ Branch 23 → 24 taken 5 times.
✓ Branch 23 → 28 taken 2 times.
7 if (q.exec() && q.next())
88
1/1
✓ Branch 24 → 25 taken 5 times.
5 return entryOf(q);
89 2 return std::nullopt;
90 7 }
91
92 5 bool remove(QSqlDatabase &db, qint64 id) {
93
1/1
✓ Branch 2 → 3 taken 5 times.
5 QSqlQuery q(db);
94
1/1
✓ Branch 6 → 7 taken 5 times.
5 q.prepare(QStringLiteral("DELETE FROM conflict_history WHERE id = ?"));
95
1/1
✓ Branch 11 → 12 taken 5 times.
5 q.addBindValue(id);
96
4/6
✓ Branch 13 → 14 taken 5 times.
✓ Branch 14 → 15 taken 5 times.
✗ Branch 14 → 18 not taken.
✓ Branch 15 → 16 taken 5 times.
✓ Branch 16 → 17 taken 5 times.
✗ Branch 16 → 18 not taken.
10 return q.exec() && q.numRowsAffected() > 0;
97 5 }
98
99 } // namespace ConflictHistory
100