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: 90.9% 80 / 0 / 88
Functions: 88.9% 8 / 0 / 9
Branches: 63.6% 75 / 0 / 118

presentation/AddressPickerModel.cpp
Line Branch Exec Source
1 #include "AddressPickerModel.h"
2 #include "ComposeLog.h"
3
4 #include "data/ContactIndex.h"
5 #include "data/ContactQueries.h"
6 #include "data/ContactStore.h"
7
8 #include <QElapsedTimer>
9 #include <QMetaObject>
10 #include <QPointer>
11 #include <QSet>
12
13 namespace {
14
15 21 QString initialsOf(const QString &name) {
16 21 QString initials;
17
4/5
✓ Branch 5 → 6 taken 21 times.
✓ Branch 6 → 7 taken 21 times.
✓ Branch 7 → 8 taken 21 times.
✓ Branch 22 → 9 taken 42 times.
✗ Branch 22 → 23 not taken.
42 for (const QString &word : name.split(QLatin1Char(' '), Qt::SkipEmptyParts)) {
18
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 42 times.
42 if (!word.at(0).isLetter()) continue;
19
1/1
✓ Branch 16 → 17 taken 42 times.
42 initials.append(word.at(0).toUpper());
20
2/2
✓ Branch 18 → 19 taken 21 times.
✓ Branch 18 → 20 taken 21 times.
42 if (initials.size() == 2) break;
21 21 }
22 21 return initials;
23 ✗ }
24
25 21 QVariantMap rowMap(QSqlDatabase db, const ContactQueries::Row &row, bool recent) {
26 21 QStringList addresses;
27
5/6
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 10 taken 18 times.
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 10 not taken.
✓ Branch 4 → 5 taken 3 times.
✓ Branch 5 → 6 taken 3 times.
21 if (row.addressCount > 1 && row.cardId > 0) addresses = ContactQueries::cardAddresses(db, row.cardId);
28
3/3
✓ Branch 11 → 12 taken 18 times.
✓ Branch 11 → 13 taken 3 times.
✓ Branch 12 → 13 taken 18 times.
21 if (addresses.isEmpty()) addresses.append(row.primaryAddress);
29
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 21 times.
21 const QString name = row.displayName.isEmpty() ? row.primaryAddress : row.displayName;
30 42 return {{QStringLiteral("key"), row.key},
31 42 {QStringLiteral("name"), name},
32 42 {QStringLiteral("address"), addresses.first()},
33 42 {QStringLiteral("addresses"), addresses},
34 42 {QStringLiteral("book"), row.bookName},
35 42 {QStringLiteral("recent"), recent},
36
1/1
✓ Branch 46 → 47 taken 21 times.
42 {QStringLiteral("initials"), initialsOf(name)},
37 42 {QStringLiteral("avatarColor"),
38
4/7
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 21 times.
✓ Branch 54 → 55 taken 21 times.
✓ Branch 58 → 59 taken 168 times.
✓ Branch 58 → 60 taken 21 times.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 88 not taken.
231 ContactIndex::avatarColorIndex(row.collected ? row.primaryAddress : row.uid)}};
39 210 }
40
41 } // namespace
42
43
2/2
✓ Branch 7 → 8 taken 795 times.
✓ Branch 8 → 9 taken 795 times.
795 AddressPickerModel::AddressPickerModel(QObject *parent) : QObject(parent) { m_pool.setMaxThreadCount(1); }
44
45 795 AddressPickerModel::~AddressPickerModel() {
46 795 m_pool.clear();
47 795 m_pool.waitForDone();
48 795 }
49
50 8 void AddressPickerModel::request(const QString &filter, qint64 groupBookId, const QString &group) {
51 8 const quint64 generation = ++m_generation;
52
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 9 taken 8 times.
8 if (m_databasePath.isEmpty()) {
53 ✗ m_rows.clear();
54 ✗ m_groups.clear();
55 ✗ emit rowsChanged();
56 ✗ return;
57 }
58 8 m_loading = true;
59
1/1
✓ Branch 9 → 10 taken 8 times.
8 emit rowsChanged();
60 8 const QString path = m_databasePath;
61
2/2
✓ Branch 11 → 12 taken 8 times.
✓ Branch 12 → 13 taken 8 times.
8 const QString words = filter.left(64).trimmed();
62
1/1
✓ Branch 14 → 15 taken 8 times.
8 QPointer<AddressPickerModel> self(this);
63 // Latest first: a queued request for older words is dropped.
64
1/1
✓ Branch 15 → 16 taken 8 times.
8 m_pool.clear();
65
1/7
✓ Branch 20 → 21 taken 8 times.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
8 m_pool.start([self, generation, path, words, groupBookId, group] {
66 8 QElapsedTimer timer;
67 8 timer.start();
68 8 QVariantList rows;
69 8 QVariantList groups;
70
3/4
✓ Branch 3 → 4 taken 8 times.
✓ Branch 4 → 5 taken 8 times.
✓ Branch 5 → 6 taken 8 times.
✗ Branch 5 → 78 not taken.
8 if (ContactStore store; store.open(path)) {
71
1/1
✓ Branch 6 → 7 taken 8 times.
8 QSqlDatabase db = store.database();
72 8 QSet<QString> seen;
73 14 const auto add = [&](const QList<ContactQueries::Row> &page, bool recent) {
74
2/2
✓ Branch 30 → 4 taken 21 times.
✓ Branch 30 → 31 taken 14 times.
35 for (const ContactQueries::Row &row : page) {
75
4/8
✓ Branch 6 → 7 taken 21 times.
✗ Branch 6 → 12 not taken.
✓ Branch 9 → 10 taken 21 times.
✗ Branch 9 → 12 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 21 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 21 times.
21 if (row.primaryAddress.isEmpty() || row.kind == QLatin1String("group") || seen.contains(row.key)) continue;
76
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 21 times.
21 if (rows.size() >= MaxRows) return;
77
1/1
✓ Branch 19 → 20 taken 21 times.
21 seen.insert(row.key);
78
3/3
✓ Branch 20 → 21 taken 21 times.
✓ Branch 21 → 22 taken 21 times.
✓ Branch 23 → 24 taken 21 times.
21 rows.append(rowMap(db, row, recent));
79 }
80 8 };
81 8 ContactQueries::View view;
82
2/2
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 7 times.
8 if (!group.isEmpty()) {
83 1 view.kind = ContactQueries::ViewKind::Group;
84 1 view.bookId = groupBookId;
85 1 view.group = group;
86
2/2
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 26 taken 1 time.
7 } else if (words.isEmpty()) {
87 6 ContactQueries::View frequent;
88 6 frequent.kind = ContactQueries::ViewKind::Frequent;
89
3/3
✓ Branch 16 → 17 taken 6 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 18 → 19 taken 6 times.
6 add(ContactQueries::page(db, frequent, {}, RecentRows), true);
90 6 }
91
3/3
✓ Branch 28 → 29 taken 8 times.
✓ Branch 29 → 30 taken 8 times.
✓ Branch 30 → 31 taken 8 times.
8 add(ContactQueries::page(db, view, words, MaxRows), false);
92
6/6
✓ Branch 35 → 36 taken 8 times.
✓ Branch 36 → 37 taken 8 times.
✓ Branch 38 → 39 taken 8 times.
✓ Branch 39 → 40 taken 8 times.
✓ Branch 72 → 41 taken 8 times.
✓ Branch 72 → 73 taken 8 times.
16 for (const ContactQueries::Group &entry : ContactQueries::groups(db))
93
1/2
✓ Branch 42 → 43 taken 8 times.
✗ Branch 42 → 70 not taken.
8 if (entry.memberCount > 0)
94
1/1
✓ Branch 57 → 58 taken 8 times.
24 groups.append(QVariantMap{{QStringLiteral("bookId"), entry.bookId},
95 16 {QStringLiteral("name"), entry.name},
96
2/4
✓ Branch 61 → 62 taken 24 times.
✓ Branch 61 → 63 taken 8 times.
✗ Branch 144 → 145 not taken.
✗ Branch 144 → 146 not taken.
56 {QStringLiteral("count"), entry.memberCount}});
97 16 }
98
2/10
✓ Branch 79 → 80 taken 8 times.
✗ Branch 83 → 84 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 86 → 87 not taken.
✗ Branch 87 → 88 not taken.
✗ Branch 89 → 90 not taken.
✗ Branch 90 → 91 not taken.
✗ Branch 92 → 93 not taken.
✗ Branch 96 → 81 not taken.
✓ Branch 96 → 97 taken 8 times.
8 qCInfo(lcCompose) << "address picker rows" << rows.size() << "groups" << groups.size() << "ms" << timer.elapsed();
99
1/1
✓ Branch 101 → 102 taken 8 times.
8 QMetaObject::invokeMethod(
100 8 self.data(),
101
0/4
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 195 not taken.
✗ Branch 196 → 197 not taken.
✗ Branch 196 → 198 not taken.
16 [self, generation, rows, groups] {
102
5/6
✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 7 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 7 times.
8 if (!self || generation != self->m_generation) return;
103 7 self->m_rows = rows;
104 7 self->m_groups = groups;
105 7 self->m_loading = false;
106 7 emit self->rowsChanged();
107 },
108 Qt::QueuedConnection);
109
1/5
✓ Branch 55 → 56 taken 8 times.
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 169 not taken.
✗ Branch 167 → 168 not taken.
✗ Branch 167 → 169 not taken.
40 });
110 8 }
111
112 ✗ bool AddressPickerModel::waitForDone(int timeoutMs) { return m_pool.waitForDone(timeoutMs); }
113