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: 92.2% 59 / 0 / 64
Functions: 91.7% 11 / 0 / 12
Branches: 74.2% 115 / 0 / 155

service/DavNetworkLimits.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QNetworkReply>
4 #include <QNetworkRequest>
5 #include <QTimer>
6 #include <QUrl>
7
8 namespace DavNetworkLimits {
9
10 inline constexpr qint64 MaxResponseBytes = 10 * 1024 * 1024;
11 inline constexpr int RequestTimeoutMs = 30000;
12 inline constexpr const char *FailureProperty = "mailjdDavNetworkFailure";
13
14 12 inline QString responseTooLargeMessage(qint64 bytes) {
15 24 return QStringLiteral("DAV response too large (%1 bytes, limit %2 bytes)")
16
1/1
✓ Branch 6 → 7 taken 12 times.
36 .arg(bytes)
17
1/1
✓ Branch 8 → 9 taken 12 times.
24 .arg(MaxResponseBytes);
18 }
19
20 11 inline void failReply(QNetworkReply *reply, const QString &error) {
21
6/12
✓ Branch 2 → 3 taken 11 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 11 times.
✓ Branch 4 → 5 taken 11 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 11 times.
✓ Branch 8 → 9 taken 11 times.
✗ Branch 8 → 10 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 11 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
11 if (!reply || reply->property(FailureProperty).isValid())
22 ✗ return;
23
1/1
✓ Branch 13 → 14 taken 11 times.
11 reply->setProperty(FailureProperty, error);
24 11 reply->abort();
25 }
26
27 2485 inline void checkResponseSize(QNetworkReply *reply) {
28
8/12
✓ Branch 2 → 3 taken 2485 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 2485 times.
✓ Branch 4 → 5 taken 2485 times.
✓ Branch 5 → 6 taken 33 times.
✓ Branch 5 → 7 taken 2452 times.
✓ Branch 8 → 9 taken 2485 times.
✗ Branch 8 → 10 not taken.
✓ Branch 10 → 11 taken 33 times.
✓ Branch 10 → 12 taken 2452 times.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
2485 if (!reply || reply->property(FailureProperty).isValid())
29 44 return;
30
31 const QVariant contentLength =
32
1/1
✓ Branch 12 → 13 taken 2452 times.
2452 reply->header(QNetworkRequest::ContentLengthHeader);
33
3/3
✓ Branch 13 → 14 taken 2452 times.
✓ Branch 14 → 15 taken 43 times.
✓ Branch 14 → 23 taken 2409 times.
2452 if (contentLength.isValid()) {
34 43 bool ok = false;
35
1/1
✓ Branch 15 → 16 taken 43 times.
43 const qint64 declaredSize = contentLength.toLongLong(&ok);
36
3/4
✓ Branch 16 → 17 taken 43 times.
✗ Branch 16 → 22 not taken.
✓ Branch 17 → 18 taken 11 times.
✓ Branch 17 → 22 taken 32 times.
43 if (ok && declaredSize > MaxResponseBytes) {
37
2/2
✓ Branch 18 → 19 taken 11 times.
✓ Branch 19 → 20 taken 11 times.
11 failReply(reply, responseTooLargeMessage(declaredSize));
38 11 return;
39 }
40 }
41
42
1/1
✓ Branch 23 → 24 taken 2441 times.
2441 const qint64 buffered = reply->bytesAvailable();
43
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 29 taken 2441 times.
2441 if (buffered > MaxResponseBytes)
44 ✗ failReply(reply, responseTooLargeMessage(buffered));
45 2452 }
46
47 1224 inline void apply(QNetworkReply *reply) {
48
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1224 times.
1224 if (!reply)
49 ✗ return;
50
51
2/5
✓ Branch 5 → 6 taken 1224 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1224 times.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
1224 auto *timer = new QTimer(reply);
52 1224 timer->setSingleShot(true);
53
1/1
✓ Branch 9 → 10 taken 1224 times.
1224 QObject::connect(timer, &QTimer::timeout, reply, [reply]() {
54 ✗ failReply(reply, QStringLiteral("DAV request timed out"));
55 ✗ });
56
1/1
✓ Branch 11 → 12 taken 1224 times.
1224 QObject::connect(reply, &QNetworkReply::finished, timer, &QTimer::stop);
57 1224 timer->start(RequestTimeoutMs);
58
59 1224 QObject::connect(reply, &QNetworkReply::metaDataChanged, reply,
60
1/1
✓ Branch 14 → 15 taken 1224 times.
2424 [reply]() { checkResponseSize(reply); });
61 1224 QObject::connect(reply, &QNetworkReply::readyRead, reply,
62
1/1
✓ Branch 16 → 17 taken 1224 times.
1303 [reply]() { checkResponseSize(reply); });
63
1/1
✓ Branch 18 → 19 taken 1224 times.
2430 QTimer::singleShot(0, reply, [reply]() { checkResponseSize(reply); });
64 }
65
66 1256 inline QString failureReason(QNetworkReply *reply) {
67
4/8
✓ Branch 2 → 3 taken 1256 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 1256 times.
✓ Branch 4 → 6 taken 1256 times.
✓ Branch 7 → 8 taken 1256 times.
✗ Branch 7 → 9 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
2512 return reply ? reply->property(FailureProperty).toString() : QString();
68 }
69
70 // The DAV clients follow redirects only within the same origin. Qt compares
71 // the port literally, so a configured "https://host:443" would reject the
72 // server's own redirect to "https://host/…" ("Insecure redirect", F93-17).
73 // Requests therefore use the URL without its scheme's default port; the
74 // stored account URL (part of the keyring identity) is left untouched.
75 741 inline QString requestServerUrl(const QString &serverUrl) {
76
1/1
✓ Branch 2 → 3 taken 741 times.
741 QUrl url(serverUrl);
77
10/12
✓ Branch 4 → 5 taken 741 times.
✓ Branch 6 → 7 taken 669 times.
✓ Branch 6 → 9 taken 72 times.
✓ Branch 7 → 8 taken 669 times.
✓ Branch 8 → 9 taken 633 times.
✓ Branch 8 → 15 taken 36 times.
✓ Branch 12 → 13 taken 72 times.
✓ Branch 12 → 16 taken 633 times.
✓ Branch 21 → 22 taken 37 times.
✓ Branch 21 → 23 taken 704 times.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
2259 if ((url.scheme() == QLatin1String("https") && url.port() == 443) ||
78
7/10
✓ Branch 10 → 11 taken 705 times.
✓ Branch 13 → 14 taken 72 times.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 71 times.
✓ Branch 17 → 18 taken 705 times.
✓ Branch 17 → 19 taken 36 times.
✓ Branch 19 → 20 taken 741 times.
✗ Branch 19 → 21 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
1518 (url.scheme() == QLatin1String("http") && url.port() == 80))
79
1/1
✓ Branch 22 → 23 taken 37 times.
37 url.setPort(-1);
80
1/1
✓ Branch 24 → 25 taken 741 times.
1482 return url.toString();
81 741 }
82
83 5394 inline int effectivePort(const QUrl &url) {
84 5394 const int port = url.port();
85
2/2
✓ Branch 3 → 4 taken 1006 times.
✓ Branch 3 → 5 taken 4388 times.
5394 if (port >= 0) return port;
86
3/3
✓ Branch 5 → 6 taken 4388 times.
✓ Branch 10 → 11 taken 4370 times.
✓ Branch 10 → 12 taken 18 times.
8776 return url.scheme().compare(QStringLiteral("https"), Qt::CaseInsensitive) == 0 ? 443 : 80;
87 }
88
89 // Resolves `href` against the DAV server URL and accepts it only on the
90 // same origin (scheme, host, effective port) without user info; "" when
91 // rejected. Shared by the CalDAV and DAV-Push clients.
92 2713 inline QString resolveSameOrigin(const QString &serverUrl, const QString &href) {
93
1/1
✓ Branch 2 → 3 taken 2713 times.
2713 const QUrl server(serverUrl);
94 2713 QUrl base = server;
95
7/7
✓ Branch 5 → 6 taken 2713 times.
✓ Branch 8 → 9 taken 2713 times.
✓ Branch 10 → 11 taken 2711 times.
✓ Branch 10 → 20 taken 2 times.
✓ Branch 14 → 15 taken 2711 times.
✓ Branch 15 → 16 taken 2711 times.
✓ Branch 16 → 17 taken 2711 times.
5424 if (!base.path().endsWith(QLatin1Char('/'))) base.setPath(base.path() + QLatin1Char('/'));
96
1/1
✓ Branch 20 → 21 taken 2713 times.
2713 const QUrl candidate(href);
97
4/4
✓ Branch 21 → 22 taken 2713 times.
✓ Branch 22 → 23 taken 1816 times.
✓ Branch 22 → 24 taken 897 times.
✓ Branch 23 → 25 taken 1816 times.
2713 const QUrl resolved = candidate.isRelative() ? base.resolved(candidate) : candidate;
98
10/14
✓ Branch 27 → 28 taken 2712 times.
✓ Branch 28 → 29 taken 2712 times.
✓ Branch 30 → 31 taken 2710 times.
✓ Branch 30 → 48 taken 2 times.
✓ Branch 36 → 37 taken 2690 times.
✓ Branch 36 → 48 taken 20 times.
✓ Branch 60 → 61 taken 2712 times.
✓ Branch 60 → 62 taken 1 time.
✓ Branch 62 → 63 taken 27 times.
✓ Branch 62 → 64 taken 2686 times.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
10845 if (!resolved.isValid() || resolved.scheme().compare(server.scheme(), Qt::CaseInsensitive) != 0 ||
99
6/10
✓ Branch 32 → 33 taken 2710 times.
✓ Branch 34 → 35 taken 2710 times.
✓ Branch 56 → 57 taken 2710 times.
✓ Branch 56 → 58 taken 3 times.
✓ Branch 58 → 59 taken 2712 times.
✓ Branch 58 → 60 taken 1 time.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 100 not taken.
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
8133 resolved.host().compare(server.host(), Qt::CaseInsensitive) != 0 ||
100
12/14
✓ Branch 25 → 26 taken 2713 times.
✓ Branch 26 → 27 taken 2712 times.
✓ Branch 26 → 48 taken 1 time.
✓ Branch 37 → 38 taken 2690 times.
✓ Branch 38 → 39 taken 2690 times.
✓ Branch 39 → 40 taken 2689 times.
✓ Branch 39 → 48 taken 1 time.
✓ Branch 41 → 42 taken 2689 times.
✓ Branch 43 → 44 taken 2687 times.
✓ Branch 43 → 48 taken 2 times.
✓ Branch 54 → 55 taken 2710 times.
✓ Branch 54 → 56 taken 3 times.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 95 not taken.
13514 effectivePort(resolved) != effectivePort(server) || !resolved.userName().isEmpty() ||
101
7/9
✓ Branch 45 → 46 taken 2687 times.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 49 taken 2686 times.
✓ Branch 50 → 51 taken 2687 times.
✓ Branch 50 → 52 taken 26 times.
✓ Branch 52 → 53 taken 2689 times.
✓ Branch 52 → 54 taken 24 times.
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 90 not taken.
5400 !resolved.password().isEmpty())
102 27 return {};
103
1/1
✓ Branch 65 → 66 taken 2686 times.
2686 return resolved.toString();
104 2713 }
105
106 } // namespace DavNetworkLimits
107