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: 77.3% 75 / 0 / 97
Functions: 83.3% 10 / 0 / 12
Branches: 61.6% 93 / 0 / 151

service/DavPushServiceTest.cpp
Line Branch Exec Source
1 #include "DavPushServiceTest.h"
2 #include "AuthenticatedRequest.h"
3
4 #include "NtfyPushReceiver.h"
5 #include "WebPushPayloadCodec.h"
6
7 #include <QLoggingCategory>
8 #include <QNetworkAccessManager>
9 #include <QNetworkReply>
10 #include <QNetworkRequest>
11 #include <QRandomGenerator>
12 #include <QUrl>
13
14
4/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 8 taken 2 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.
3 Q_LOGGING_CATEGORY(lcDavPushTest, "mailjd.davpush.servicetest")
15
16
1/1
✓ Branch 5 → 6 taken 4 times.
4 DavPushServiceTest::DavPushServiceTest(QObject *parent) : QObject(parent) {
17
3/6
✓ Branch 11 → 12 taken 4 times.
✓ Branch 12 → 13 taken 4 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 4 times.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
4 m_nam = new QNetworkAccessManager(this);
18
1/1
✓ Branch 15 → 16 taken 4 times.
4 m_timeout.setSingleShot(true);
19
1/1
✓ Branch 16 → 17 taken 4 times.
4 m_timeout.setInterval(15000);
20
1/1
✓ Branch 17 → 18 taken 4 times.
4 connect(&m_timeout, &QTimer::timeout, this, [this] {
21 ✗ finish(m_published ? Result::NoDelivery : Result::Timeout);
22 ✗ });
23 4 }
24
25 5 DavPushServiceTest::~DavPushServiceTest() {
26 4 cancel();
27 5 }
28
29 1 void DavPushServiceTest::setNetworkAccessManager(QNetworkAccessManager *nam) {
30
4/8
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 6 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 10 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
1 if (m_nam && m_nam->parent() == this) delete m_nam;
31 1 m_nam = nam;
32
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 12 not taken.
1 if (m_nam) m_nam->setParent(this);
33 1 }
34
35 4 void DavPushServiceTest::start(const QString &server, const QByteArray &token) {
36
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4 times.
5 if (m_running) return;
37
1/1
✓ Branch 4 → 5 taken 4 times.
4 const QUrl url(server);
38
12/19
✓ Branch 5 → 6 taken 4 times.
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 15 not taken.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 10 → 11 taken 3 times.
✓ Branch 10 → 15 taken 1 time.
✓ Branch 12 → 13 taken 3 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 3 times.
✓ Branch 17 → 18 taken 3 times.
✓ Branch 17 → 19 taken 1 time.
✓ Branch 19 → 20 taken 4 times.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 26 taken 3 times.
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 89 not taken.
✗ Branch 92 → 93 not taken.
✗ Branch 92 → 94 not taken.
7 if (!url.isValid() || url.scheme() != QLatin1String("https") || url.host().isEmpty()) {
39
1/1
✓ Branch 23 → 24 taken 1 time.
1 emit finished(Result::InvalidUrl, {});
40 1 return;
41 }
42 3 m_running = true;
43 3 m_published = false;
44 3 m_server = server;
45 3 m_token = token;
46
1/1
✓ Branch 28 → 29 taken 3 times.
3 QByteArray random(16, Qt::Uninitialized);
47
4/5
✓ Branch 29 → 30 taken 3 times.
✗ Branch 29 → 128 not taken.
✓ Branch 30 → 31 taken 3 times.
✓ Branch 31 → 32 taken 3 times.
✓ Branch 32 → 33 taken 3 times.
3 QRandomGenerator::system()->generate(random.begin(), random.end());
48 // Same topic form as real receivers (servers with subscriber-based rate
49 // limiting refuse other UnifiedPush names).
50 static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
51 3 m_channel = QStringLiteral("up");
52
5/6
✓ Branch 40 → 41 taken 36 times.
✗ Branch 40 → 100 not taken.
✓ Branch 41 → 42 taken 36 times.
✓ Branch 44 → 45 taken 36 times.
✓ Branch 46 → 40 taken 36 times.
✓ Branch 46 → 47 taken 3 times.
39 for (int i = 0; i < 12; ++i) m_channel.append(QLatin1Char(alphabet[QRandomGenerator::system()->bounded(62)]));
53
2/2
✓ Branch 47 → 48 taken 3 times.
✓ Branch 48 → 49 taken 3 times.
3 m_probe = "mailjd-test-" + random.toHex();
54
9/14
✓ Branch 53 → 54 taken 2 times.
✓ Branch 53 → 56 taken 1 time.
✓ Branch 54 → 55 taken 2 times.
✓ Branch 56 → 57 taken 1 time.
✓ Branch 57 → 58 taken 1 time.
✓ Branch 59 → 60 taken 3 times.
✓ Branch 60 → 61 taken 1 time.
✓ Branch 60 → 63 taken 2 times.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 1 time.
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 109 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
3 m_receiver = m_receiverFactory ? m_receiverFactory(this) : new NtfyPushReceiver(this);
55
1/1
✓ Branch 64 → 65 taken 3 times.
3 connect(m_receiver, &PushReceiver::stateChanged, this, [this] {
56
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 6 times.
6 if (!m_receiver) return;
57 6 const auto failure = m_receiver->failure();
58
1/3
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 13 taken 6 times.
✗ Branch 10 → 11 not taken.
6 if (failure == PushReceiver::Failure::Tls) finish(Result::Tls, m_receiver->failureDetail());
59
3/3
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 19 taken 5 times.
✓ Branch 16 → 17 taken 1 time.
6 else if (failure == PushReceiver::Failure::Authentication) finish(Result::Authentication, m_receiver->failureDetail());
60
3/4
✓ Branch 19 → 20 taken 4 times.
✓ Branch 19 → 21 taken 1 time.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 26 taken 4 times.
5 else if (failure == PushReceiver::Failure::Network || failure == PushReceiver::Failure::Protocol)
61
1/1
✓ Branch 23 → 24 taken 1 time.
1 finish(Result::Unreachable, m_receiver->failureDetail());
62 });
63
1/1
✓ Branch 67 → 68 taken 3 times.
3 connect(m_receiver, &PushReceiver::streamResumed, this, &DavPushServiceTest::publish);
64
1/1
✓ Branch 70 → 71 taken 3 times.
3 connect(m_receiver, &PushReceiver::messageReceived, this, [this](const QByteArray &payload) {
65
2/3
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 1 time.
1 if (payload == m_probe) finish(Result::Ok);
66 1 });
67
1/1
✓ Branch 72 → 73 taken 3 times.
3 m_timeout.start();
68 6 m_receiver->start({server, m_channel, token, {}});
69 7 }
70
71 1 void DavPushServiceTest::publish() {
72
2/4
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (m_published || !m_running) return;
73 1 m_published = true;
74
4/4
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
1 QNetworkRequest request(QUrl(m_server + QLatin1Char('/') + m_channel));
75
3/3
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
1 request.setRawHeader("Content-Type", "text/plain");
76
1/1
✓ Branch 25 → 26 taken 1 time.
3 m_publishRequest = AuthenticatedRequest::start(this, m_nam, request,
77
2/3
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
2 m_token.isEmpty() ? QByteArray() : "Bearer " + m_token, m_probe, true,
78 AuthenticatedRequest::ForeignRedirect::Refuse,
79 1 [this](AuthenticatedRequest::Result result) {
80 ✗ m_publishRequest = nullptr;
81 ✗ if (!m_running) return;
82 ✗ if (result.outcome == AuthenticatedRequest::Outcome::Unauthorized)
83 ✗ finish(Result::Authentication, QStringLiteral("publishing was refused"));
84 ✗ else if (result.outcome == AuthenticatedRequest::Outcome::RedirectedToForeignHost)
85 ✗ finish(Result::Unreachable, tr("The push server redirected to another host (%1).").arg(result.url.host()));
86 ✗ else if (result.outcome != AuthenticatedRequest::Outcome::Ok)
87 ✗ finish(Result::Unreachable, QStringLiteral("publishing failed"));
88
2/2
✓ Branch 26 → 27 taken 1 time.
✓ Branch 27 → 28 taken 1 time.
1 });
89 1 }
90
91 3 void DavPushServiceTest::finish(Result result, const QString &detail) {
92
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 3 times.
3 if (!m_running) return;
93 3 m_running = false;
94 3 m_timeout.stop();
95
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 12 taken 2 times.
3 if (m_publishRequest) {
96 1 m_publishRequest->cancel();
97 1 m_publishRequest->deleteLater();
98 1 m_publishRequest = nullptr;
99 }
100 3 m_token.clear();
101
1/2
✓ Branch 14 → 15 taken 3 times.
✗ Branch 14 → 22 not taken.
3 if (m_receiver) {
102 3 m_receiver->disconnect(this);
103 3 m_receiver->stop();
104 3 m_receiver->deleteLater();
105 3 m_receiver = nullptr;
106 }
107
7/7
✓ Branch 22 → 23 taken 3 times.
✓ Branch 26 → 27 taken 3 times.
✓ Branch 27 → 28 taken 3 times.
✓ Branch 29 → 30 taken 3 times.
✓ Branch 30 → 31 taken 3 times.
✓ Branch 36 → 24 taken 3 times.
✓ Branch 36 → 37 taken 3 times.
6 qCInfo(lcDavPushTest) << "Push service test:" << result << detail;
108 3 emit finished(result, detail);
109 }
110
111 4 void DavPushServiceTest::cancel() {
112
1/2
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 4 not taken.
4 if (!m_running) return;
113 ✗ m_running = false;
114 ✗ m_timeout.stop();
115 ✗ if (m_publishRequest) {
116 ✗ m_publishRequest->cancel();
117 ✗ m_publishRequest->deleteLater();
118 ✗ m_publishRequest = nullptr;
119 }
120 ✗ m_token.clear();
121 ✗ if (m_receiver) {
122 ✗ m_receiver->disconnect(this);
123 ✗ m_receiver->stop();
124 ✗ m_receiver->deleteLater();
125 ✗ m_receiver = nullptr;
126 }
127 }
128