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: 98.1% 51 / 0 / 52
Functions: 100.0% 6 / 0 / 6
Branches: 81.3% 100 / 0 / 123

app/core/ContactPhotoFetch.cpp
Line Branch Exec Source
1 #include "ContactPhotoFetch.h"
2
3 #include "data/ContactQueries.h"
4 #include "service/CardDavClient.h"
5 #include "service/DavResponse.h"
6
7 #include <QLoggingCategory>
8 #include <QTimer>
9 #include <QUrl>
10
11
4/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 8 taken 3 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
4 Q_LOGGING_CATEGORY(lcContactPhotoFetch, "mailjd.contacts.photo")
12
13 73 ContactPhotoFetch::ContactPhotoFetch(ContactStore *store, CardDavClient *client, qint64 bookId, QObject *parent)
14 73 : QObject(parent), m_store(store), m_client(client), m_bookId(bookId) {
15
1/1
✓ Branch 6 → 7 taken 73 times.
73 connect(m_client, &CardDavClient::resourceResponse, this, &ContactPhotoFetch::onResponse);
16 73 }
17
18 10 QString ContactPhotoFetch::sameOriginUrl(const QString &cardHref, const QString &photoUri) {
19
1/1
✓ Branch 2 → 3 taken 10 times.
10 const QUrl base(cardHref);
20
2/2
✓ Branch 3 → 4 taken 10 times.
✓ Branch 4 → 5 taken 10 times.
10 const QUrl url = base.resolved(QUrl(photoUri));
21
2/2
✓ Branch 6 → 7 taken 10 times.
✓ Branch 7 → 8 taken 10 times.
10 const QString scheme = url.scheme().toLower();
22
9/13
✓ Branch 9 → 10 taken 10 times.
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 23 taken 1 time.
✓ Branch 12 → 13 taken 9 times.
✓ Branch 14 → 15 taken 9 times.
✗ Branch 14 → 23 not taken.
✓ Branch 15 → 16 taken 9 times.
✓ Branch 16 → 17 taken 9 times.
✗ Branch 16 → 23 not taken.
✓ Branch 27 → 28 taken 2 times.
✓ Branch 27 → 29 taken 8 times.
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 77 not taken.
38 if (!base.isValid() || base.host().isEmpty() || !url.isValid() ||
23
6/6
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 24 taken 7 times.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 1 time.
✓ Branch 25 → 26 taken 9 times.
✓ Branch 25 → 27 taken 1 time.
19 (scheme != QLatin1String("https") && scheme != QLatin1String("http")))
24 2 return {};
25
2/2
✓ Branch 31 → 32 taken 7 times.
✓ Branch 31 → 33 taken 1 time.
8 const int defaultPort = scheme == QLatin1String("https") ? 443 : 80;
26
12/22
✓ Branch 34 → 35 taken 8 times.
✓ Branch 35 → 36 taken 8 times.
✓ Branch 37 → 38 taken 7 times.
✓ Branch 37 → 48 taken 1 time.
✓ Branch 39 → 40 taken 7 times.
✓ Branch 41 → 42 taken 7 times.
✓ Branch 43 → 44 taken 5 times.
✓ Branch 43 → 48 taken 2 times.
✓ Branch 51 → 52 taken 7 times.
✓ Branch 51 → 53 taken 1 time.
✓ Branch 53 → 54 taken 8 times.
✗ Branch 53 → 55 not taken.
✓ Branch 55 → 56 taken 8 times.
✗ Branch 55 → 57 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 87 not taken.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 96 not taken.
28 const bool same = scheme == base.scheme().toLower() && url.host().compare(base.host(), Qt::CaseInsensitive) == 0 &&
27
5/6
✓ Branch 44 → 45 taken 5 times.
✓ Branch 45 → 46 taken 5 times.
✓ Branch 46 → 47 taken 5 times.
✗ Branch 46 → 48 not taken.
✓ Branch 49 → 50 taken 7 times.
✓ Branch 49 → 51 taken 1 time.
13 url.port(defaultPort) == base.port(defaultPort);
28
3/3
✓ Branch 57 → 58 taken 5 times.
✓ Branch 57 → 60 taken 3 times.
✓ Branch 59 → 61 taken 5 times.
8 return same ? url.toString(QUrl::FullyEncoded) : QString();
29 10 }
30
31 73 void ContactPhotoFetch::start() {
32
1/1
✓ Branch 2 → 3 taken 73 times.
73 m_pending = m_store->pendingPhotos(m_bookId, MaxPerRun);
33
2/2
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 22 taken 71 times.
73 if (!m_pending.isEmpty())
34
8/8
✓ Branch 7 → 8 taken 2 times.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 14 → 15 taken 2 times.
✓ Branch 16 → 17 taken 2 times.
✓ Branch 20 → 9 taken 2 times.
✓ Branch 20 → 21 taken 2 times.
4 qCInfo(lcContactPhotoFetch) << "Book" << m_bookId << "photos to fetch:" << m_pending.size();
35 // Queued: the caller connects to finished() before or after start().
36
1/1
✓ Branch 22 → 23 taken 73 times.
73 QTimer::singleShot(0, this, &ContactPhotoFetch::next);
37 73 }
38
39 76 void ContactPhotoFetch::next() {
40
2/2
✓ Branch 32 → 3 taken 4 times.
✓ Branch 32 → 33 taken 73 times.
77 while (!m_pending.isEmpty()) {
41
1/1
✓ Branch 3 → 4 taken 4 times.
4 m_current = m_pending.takeFirst();
42
1/1
✓ Branch 6 → 7 taken 4 times.
4 const QString url = sameOriginUrl(m_current.href, m_current.uri);
43
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 25 taken 3 times.
4 if (url.isEmpty()) {
44 // D-15: foreign or unusable URI — never requested.
45
7/7
✓ Branch 9 → 10 taken 1 time.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 20 → 11 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
2 qCDebug(lcContactPhotoFetch) << "Card" << m_current.cardId << "photo URI is not on the book's origin";
46
1/1
✓ Branch 22 → 23 taken 1 time.
1 m_store->setFetchedPhoto(m_current.cardId, m_current.uri, {});
47 1 continue;
48 1 }
49 3 ++m_requests;
50
1/1
✓ Branch 25 → 26 taken 3 times.
3 m_request = m_client->getResource(url);
51 3 return;
52 4 }
53 73 m_request = 0;
54 73 emit finished(m_keys);
55 }
56
57 3 void ContactPhotoFetch::onResponse(const DavResponse &response) {
58
2/4
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (m_request == 0 || response.request != m_request)
59 ✗ return;
60
1/1
✓ Branch 5 → 6 taken 3 times.
3 emit progressed();
61 3 QByteArray bytes;
62
7/10
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 13 not taken.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 13 taken 1 time.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 13 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 2 times.
✓ Branch 14 → 16 taken 1 time.
3 if (response.status >= 200 && response.status < 300 && !response.body.isEmpty() && response.body.size() <= MaxBytes)
63 2 bytes = response.body;
64 else
65
8/8
✓ Branch 16 → 17 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 31 → 18 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
2 qCInfo(lcContactPhotoFetch) << "Card" << m_current.cardId << "photo not fetched: status" << response.status
66
2/2
✓ Branch 25 → 26 taken 1 time.
✓ Branch 27 → 28 taken 1 time.
1 << "bytes" << response.body.size();
67
1/1
✓ Branch 33 → 34 taken 3 times.
3 m_store->setFetchedPhoto(m_current.cardId, m_current.uri, bytes);
68
2/2
✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 40 taken 1 time.
3 if (!bytes.isEmpty())
69
2/2
✓ Branch 36 → 37 taken 2 times.
✓ Branch 37 → 38 taken 2 times.
2 m_keys.append(ContactQueries::cardKey(m_bookId, m_current.uid));
70
1/1
✓ Branch 40 → 41 taken 3 times.
3 next();
71 3 }
72