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: 96.3% 341 / 0 / 354
Functions: 88.6% 39 / 0 / 44
Branches: 82.1% 440 / 0 / 536

app/core/DavPushCoordinator.cpp
Line Branch Exec Source
1 #include "DavPushCoordinator.h"
2
3 #include "CalendarSyncCoordinator.h"
4 #include "DavPushDiagnostics.h"
5 #include "DavPushStatistics.h"
6 #include "data/DavPushSettings.h"
7 #include "data/DavPushStore.h"
8 #include "service/NetworkLifecycleCoordinator.h"
9 #include "service/NtfyPushReceiver.h"
10 #include "service/UnifiedPushReceiver.h"
11
12 #include <QDateTime>
13 #include <QLoggingCategory>
14 #include <QSettings>
15 #include <QUrl>
16
17 Q_DECLARE_LOGGING_CATEGORY(lcDavPush)
18
19 namespace {
20 constexpr int kReconcileIntervalMs = 5 * 60 * 1000;
21
22 68 QString primaryReason(unsigned reasons) {
23
2/2
✓ Branch 2 → 3 taken 33 times.
✓ Branch 2 → 8 taken 35 times.
101 if (reasons & DavSyncReasonManual) return QStringLiteral("manual");
24
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 14 taken 34 times.
36 if (reasons & DavSyncReasonPush) return QStringLiteral("push");
25
2/2
✓ Branch 14 → 15 taken 3 times.
✓ Branch 14 → 20 taken 31 times.
37 if (reasons & DavSyncReasonRecovery) return QStringLiteral("recovery");
26
1/2
✓ Branch 20 → 21 taken 31 times.
✗ Branch 20 → 26 not taken.
62 if (reasons & DavSyncReasonInitial) return QStringLiteral("initial");
27 ✗ return QStringLiteral("poll");
28 }
29
30 2022 QHash<QString, QString> accountLabels() {
31 2022 QHash<QString, QString> labels;
32
1/1
✓ Branch 2 → 3 taken 2022 times.
2022 QSettings settings;
33
1/1
✓ Branch 7 → 8 taken 2022 times.
2022 const int count = settings.beginReadArray(QStringLiteral("carddav/accounts"));
34
2/2
✓ Branch 64 → 11 taken 623 times.
✓ Branch 64 → 65 taken 2022 times.
2645 for (int i = 0; i < count; ++i) {
35
1/1
✓ Branch 11 → 12 taken 623 times.
623 settings.setArrayIndex(i);
36
4/4
✓ Branch 16 → 17 taken 623 times.
✓ Branch 17 → 18 taken 623 times.
✓ Branch 18 → 19 taken 623 times.
✓ Branch 20 → 21 taken 623 times.
1246 const QString host = QUrl(settings.value(QStringLiteral("serverUrl")).toString()).host();
37
2/2
✓ Branch 30 → 31 taken 623 times.
✓ Branch 31 → 32 taken 623 times.
623 const QString user = settings.value(QStringLiteral("username")).toString();
38
13/19
✓ Branch 36 → 37 taken 5 times.
✓ Branch 36 → 38 taken 618 times.
✓ Branch 41 → 42 taken 618 times.
✓ Branch 42 → 43 taken 618 times.
✓ Branch 47 → 48 taken 623 times.
✓ Branch 48 → 49 taken 623 times.
✓ Branch 49 → 50 taken 623 times.
✓ Branch 55 → 56 taken 618 times.
✓ Branch 55 → 57 taken 5 times.
✓ Branch 57 → 58 taken 618 times.
✓ Branch 57 → 59 taken 5 times.
✓ Branch 59 → 60 taken 618 times.
✓ Branch 59 → 61 taken 5 times.
✗ Branch 118 → 119 not taken.
✗ Branch 118 → 120 not taken.
✗ Branch 122 → 123 not taken.
✗ Branch 122 → 124 not taken.
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 128 not taken.
1864 labels.insert(settings.value(QStringLiteral("id")).toString(), host.isEmpty() ? user : user + QStringLiteral(" @ ") + host);
39 623 }
40
1/1
✓ Branch 65 → 66 taken 2022 times.
2022 settings.endArray();
41 2022 return labels;
42 2022 }
43 } // namespace
44
45 857 DavPushCoordinator::DavPushCoordinator(const QString &storePath, Deps deps, QObject *parent)
46
2/2
✓ Branch 3 → 4 taken 857 times.
✓ Branch 9 → 10 taken 857 times.
857 : QObject(parent), m_store(std::make_unique<DavPushStore>()), m_deps(std::move(deps)) {
47
2/2
✓ Branch 12 → 13 taken 822 times.
✓ Branch 12 → 15 taken 35 times.
1787 if (!m_deps.now) m_deps.now = [] { return QDateTime::currentSecsSinceEpoch(); };
48
2/2
✓ Branch 16 → 17 taken 822 times.
✓ Branch 16 → 19 taken 35 times.
857 if (!m_deps.makeReceiver)
49 822 m_deps.makeReceiver = [](const QString &provider, QObject *parent) -> PushReceiver * {
50 ✗ if (provider == DavPushSettings::kSystemProvider) return new UnifiedPushReceiver(parent);
51 ✗ return new NtfyPushReceiver(parent);
52 822 };
53
2/2
✓ Branch 20 → 21 taken 822 times.
✓ Branch 20 → 23 taken 35 times.
857 if (!m_deps.releaseReceiver)
54 822 m_deps.releaseReceiver = [](const QString &provider, const QString &server, const QString &channel) {
55 ✗ if (provider == DavPushSettings::kSystemProvider) UnifiedPushReceiver::unregisterToken(server, channel);
56 822 };
57 857 const bool watchBus = !m_deps.findSystemDistributor;
58
2/2
✓ Branch 24 → 25 taken 821 times.
✓ Branch 24 → 27 taken 36 times.
1680 if (watchBus) m_deps.findSystemDistributor = [] { return UnifiedPushReceiver::findDistributor(); };
59
2/2
✓ Branch 28 → 29 taken 826 times.
✓ Branch 28 → 31 taken 31 times.
857 if (!m_deps.makeClient)
60 826 m_deps.makeClient = [](const QString &url, const QString &user, const QString &password) {
61 ✗ return new DavPushClient(url, user, password);
62 826 };
63
3/3
✓ Branch 32 → 33 taken 857 times.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 49 taken 856 times.
857 if (!m_store->open(storePath)) {
64
6/6
✓ Branch 34 → 35 taken 1 time.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 39 → 40 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 47 → 36 taken 1 time.
✓ Branch 47 → 48 taken 1 time.
2 qCWarning(lcDavPush) << "DAV-Push stays off: local state unavailable:" << m_store->lastError();
65 1 return;
66 }
67
1/1
✓ Branch 50 → 51 taken 856 times.
856 m_installationId = m_store->installationId();
68
1/1
✓ Branch 54 → 55 taken 856 times.
856 m_stats = std::make_unique<DavPushStatistics>(m_store.get(), m_deps.now);
69
1/1
✓ Branch 58 → 59 taken 856 times.
856 connect(m_stats.get(), &DavPushStatistics::changed, this, &DavPushCoordinator::changed);
70 // A distributor that starts or stops (KUnifiedPush login, setup) switches
71 // the push service at once instead of at the next reconcile.
72
3/3
✓ Branch 60 → 61 taken 820 times.
✓ Branch 60 → 65 taken 36 times.
✓ Branch 62 → 63 taken 820 times.
856 if (watchBus) UnifiedPushReceiver::watchDistributors(this, [this] { reconfigure(); });
73
1/1
✓ Branch 65 → 66 taken 856 times.
856 m_reconcileTimer.setInterval(kReconcileIntervalMs);
74
1/1
✓ Branch 66 → 67 taken 856 times.
856 connect(&m_reconcileTimer, &QTimer::timeout, this, &DavPushCoordinator::reconfigure);
75 ✗ }
76
77 1708 DavPushCoordinator::~DavPushCoordinator() {
78 857 shutdown();
79 1708 }
80
81 2817 bool DavPushCoordinator::isOpen() const {
82
4/6
✓ Branch 3 → 4 taken 2817 times.
✗ Branch 3 → 10 not taken.
✓ Branch 6 → 7 taken 2813 times.
✓ Branch 6 → 10 taken 4 times.
✓ Branch 8 → 9 taken 2813 times.
✗ Branch 8 → 10 not taken.
2817 return m_store && m_store->isOpen() && m_stats;
83 }
84
85 821 void DavPushCoordinator::addSource(std::unique_ptr<DavPushSource> source) {
86
5/6
✓ Branch 3 → 4 taken 821 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 820 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 820 times.
821 if (!source || m_started) return;
87 820 m_deps.sources.push_back(std::move(source));
88 }
89
90 857 void DavPushCoordinator::start() {
91
7/8
✓ Branch 3 → 4 taken 856 times.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 4 → 5 taken 856 times.
✗ Branch 4 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 855 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 855 times.
857 if (!isOpen() || m_started || m_deps.sources.empty()) return;
92 855 m_started = true;
93
3/3
✓ Branch 15 → 16 taken 1677 times.
✓ Branch 18 → 13 taken 1677 times.
✓ Branch 18 → 19 taken 855 times.
2532 for (const auto &source : m_deps.sources) connectSource(source.get());
94
2/2
✓ Branch 19 → 20 taken 821 times.
✓ Branch 19 → 25 taken 34 times.
855 if (m_deps.lifecycle) {
95
1/1
✓ Branch 20 → 21 taken 821 times.
821 connect(m_deps.lifecycle, &NetworkLifecycleCoordinator::suspendingChanged, this, [this](bool suspending) {
96 1 m_suspended = suspending;
97
6/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 9 not taken.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 4 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
2 qCInfo(lcDavPush) << (suspending ? "Suspend: pausing push" : "Resume: restoring push");
98 1 reconfigure();
99 1 });
100
1/1
✓ Branch 22 → 23 taken 821 times.
821 connect(m_deps.lifecycle, &NetworkLifecycleCoordinator::recoveryRequested, this, [this] {
101 // Network back / resume: confirm receivers, renew expired
102 // subscriptions (reconfigure), then catch up every account.
103 1 m_suspended = false;
104 1 reconfigure();
105
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 14 not taken.
1 if (DavPushSettings::backgroundSyncEnabled())
106
3/3
✓ Branch 9 → 10 taken 1 time.
✓ Branch 12 → 7 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
2 for (const auto &source : m_deps.sources) source->requestAll(DavSyncReasonRecovery);
107 1 });
108 }
109 855 m_reconcileTimer.start();
110 855 reconfigure();
111 }
112
113 1677 void DavPushCoordinator::connectSource(DavPushSource *source) {
114 1677 connect(source, &DavPushSource::discovered, this,
115
1/1
✓ Branch 2 → 3 taken 1677 times.
1677 [this, source](const QString &accountId, const QList<DavPushDiscovery> &found) {
116 36 onDiscovered(source, accountId, found);
117 36 });
118
1/1
✓ Branch 4 → 5 taken 1677 times.
1677 connect(source, &DavPushSource::syncFinished, this, &DavPushCoordinator::onSyncFinished);
119
1/1
✓ Branch 6 → 7 taken 1677 times.
1677 connect(source, &DavPushSource::batchStarted, this, &DavPushCoordinator::onBatchStarted);
120 // S96.3.7: own writes carry our registration URL (verified in G0: the own
121 // change is not delivered back; other subscriptions are still notified).
122
1/1
✓ Branch 8 → 9 taken 1677 times.
1677 QPointer<DavPushCoordinator> guard(this);
123
2/2
✓ Branch 10 → 11 taken 1677 times.
✓ Branch 11 → 12 taken 1677 times.
1677 source->setPushDontNotifyProvider([guard](const QString &accountId, const QString &path) {
124
3/6
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 3 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 3 times.
3 if (!guard || !guard->m_store) return QString();
125
1/1
✓ Branch 13 → 14 taken 3 times.
3 const auto record = guard->m_store->collection(accountId, path);
126
4/5
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 22 not taken.
✓ Branch 18 → 19 taken 3 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 22 taken 1 time.
3 return record && record->expiresAt > guard->m_deps.now() ? record->registrationUrl : QString();
127 3 });
128 1677 }
129
130 66 DavPushSource *DavPushCoordinator::sourceFor(const QString &accountId, const QString &path) const {
131
1/2
✓ Branch 25 → 4 taken 70 times.
✗ Branch 25 → 26 not taken.
70 for (const auto &source : m_deps.sources)
132
5/5
✓ Branch 6 → 7 taken 70 times.
✓ Branch 7 → 8 taken 70 times.
✓ Branch 8 → 9 taken 70 times.
✓ Branch 17 → 10 taken 106 times.
✓ Branch 17 → 18 taken 4 times.
110 for (const auto &collection : source->collections(accountId))
133
4/4
✓ Branch 12 → 13 taken 66 times.
✓ Branch 12 → 15 taken 40 times.
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 23 taken 66 times.
110 if (collection.path == path) return source.get();
134 ✗ return nullptr;
135 }
136
137 285 QSet<QString> DavPushCoordinator::selectedPaths(const QString &accountId) const {
138 285 QSet<QString> paths;
139
2/2
✓ Branch 19 → 5 taken 447 times.
✓ Branch 19 → 20 taken 285 times.
732 for (const auto &source : m_deps.sources)
140
6/6
✓ Branch 7 → 8 taken 447 times.
✓ Branch 8 → 9 taken 447 times.
✓ Branch 9 → 10 taken 447 times.
✓ Branch 12 → 13 taken 463 times.
✓ Branch 15 → 11 taken 463 times.
✓ Branch 15 → 16 taken 447 times.
910 for (const auto &collection : source->collections(accountId)) paths.insert(collection.path);
141 285 return paths;
142 ✗ }
143
144 66 void DavPushCoordinator::requestSync(const QString &accountId, const QStringList &paths, unsigned reasons) {
145
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 15 taken 61 times.
66 if (paths.isEmpty()) {
146
3/3
✓ Branch 9 → 10 taken 5 times.
✓ Branch 13 → 6 taken 5 times.
✓ Branch 13 → 14 taken 5 times.
10 for (const auto &source : m_deps.sources) source->requestSync(accountId, {}, reasons);
147 5 return;
148 }
149 61 QHash<DavPushSource *, QStringList> bySource;
150
2/2
✓ Branch 24 → 17 taken 62 times.
✓ Branch 24 → 25 taken 61 times.
123 for (const QString &path : paths)
151
4/5
✓ Branch 18 → 19 taken 62 times.
✓ Branch 19 → 20 taken 62 times.
✗ Branch 19 → 22 not taken.
✓ Branch 20 → 21 taken 62 times.
✓ Branch 21 → 22 taken 62 times.
62 if (auto *source = sourceFor(accountId, path)) bySource[source].append(path);
152
3/3
✓ Branch 28 → 29 taken 61 times.
✓ Branch 32 → 26 taken 61 times.
✓ Branch 32 → 33 taken 61 times.
122 for (auto it = bySource.cbegin(); it != bySource.cend(); ++it) it.key()->requestSync(accountId, it.value(), reasons);
153 61 }
154
155 1681 void DavPushCoordinator::shutdown() {
156 1681 m_reconcileTimer.stop();
157
2/2
✓ Branch 13 → 6 taken 169 times.
✓ Branch 13 → 14 taken 1681 times.
1850 for (const auto &account : std::as_const(m_accounts))
158
2/3
✓ Branch 8 → 9 taken 169 times.
✗ Branch 8 → 11 not taken.
✓ Branch 10 → 11 taken 169 times.
169 if (account) account->pause();
159
2/2
✓ Branch 15 → 16 taken 1680 times.
✓ Branch 15 → 18 taken 1 time.
1681 if (m_stats) m_stats->flush();
160 1681 }
161
162 2032 QString DavPushCoordinator::pauseReason() const {
163
2/2
✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 9 taken 2019 times.
2045 if (!DavPushSettings::enabled()) return QStringLiteral("disabled");
164
2/2
✓ Branch 10 → 11 taken 3 times.
✓ Branch 10 → 16 taken 2016 times.
2022 if (!DavPushSettings::backgroundSyncEnabled()) return QStringLiteral("background-off");
165
6/6
✓ Branch 17 → 18 taken 2015 times.
✓ Branch 17 → 21 taken 1 time.
✓ Branch 19 → 20 taken 1756 times.
✓ Branch 19 → 21 taken 259 times.
✓ Branch 22 → 23 taken 1756 times.
✓ Branch 22 → 28 taken 260 times.
3772 if (m_deps.networkAllowed && !m_deps.networkAllowed()) return QStringLiteral("offline");
166
2/2
✓ Branch 28 → 29 taken 2 times.
✓ Branch 28 → 34 taken 258 times.
262 if (m_suspended) return QStringLiteral("suspended");
167 258 return {};
168 }
169
170 166 DavPushAccount *DavPushCoordinator::accountFor(const QString &accountId) {
171
4/4
✓ Branch 4 → 5 taken 66 times.
✓ Branch 4 → 7 taken 100 times.
✓ Branch 9 → 10 taken 100 times.
✓ Branch 9 → 17 taken 66 times.
166 if (auto account = m_accounts.value(accountId)) return account;
172 100 DavPushAccount::Context context;
173 100 context.store = m_store.get();
174 100 context.stats = m_stats.get();
175 100 context.secrets = m_deps.secrets.get();
176 100 context.installationId = m_installationId;
177
1/1
✓ Branch 16 → 18 taken 100 times.
100 context.makeReceiver = m_deps.makeReceiver;
178
1/1
✓ Branch 18 → 19 taken 100 times.
100 context.releaseReceiver = m_deps.releaseReceiver;
179
1/1
✓ Branch 19 → 20 taken 100 times.
100 context.makeClient = m_deps.makeClient;
180
1/1
✓ Branch 20 → 21 taken 100 times.
100 context.resolveCredentials = m_deps.resolveCredentials;
181
1/1
✓ Branch 21 → 22 taken 100 times.
100 context.now = m_deps.now;
182 263 context.requestSync = [this](const QString &id, const QStringList &paths, unsigned reasons) {
183 63 requestSync(id, paths, reasons);
184 100 };
185 204 context.storedToken = [this](const QString &id, const QString &path) {
186 4 auto *source = sourceFor(id, path);
187
1/2
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 5 not taken.
4 return source ? source->storedToken(id, path) : QString();
188 100 };
189 110 context.pushHealth = [this](const QString &id, bool failing) { onPushHealth(id, failing); };
190
3/6
✓ Branch 25 → 26 taken 100 times.
✓ Branch 28 → 29 taken 100 times.
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 100 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
100 auto *account = new DavPushAccount(accountId, std::move(context), this);
191
1/1
✓ Branch 32 → 33 taken 100 times.
100 connect(account, &DavPushAccount::changed, this, &DavPushCoordinator::changed);
192
2/2
✓ Branch 34 → 35 taken 100 times.
✓ Branch 35 → 36 taken 100 times.
100 m_accounts.insert(accountId, account);
193 100 return account;
194 100 }
195
196 2180 DavPushSettings::Receiver DavPushCoordinator::effectiveReceiver() const {
197
6/6
✓ Branch 3 → 4 taken 2158 times.
✓ Branch 3 → 7 taken 22 times.
✓ Branch 5 → 6 taken 43 times.
✓ Branch 5 → 7 taken 2115 times.
✓ Branch 8 → 9 taken 43 times.
✓ Branch 8 → 12 taken 2137 times.
2180 if (DavPushSettings::useSystemService() && !m_systemDistributor.isEmpty())
198 86 return {DavPushSettings::kSystemProvider, m_systemDistributor, false, false};
199 2137 return DavPushSettings::receiver();
200 43 }
201
202 931 void DavPushCoordinator::reconfigure() {
203
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 930 times.
931 if (!m_started) return;
204
2/3
✓ Branch 5 → 6 taken 930 times.
✗ Branch 5 → 7 not taken.
✓ Branch 6 → 8 taken 930 times.
930 const QString detected = m_deps.findSystemDistributor ? m_deps.findSystemDistributor() : QString();
205
2/2
✓ Branch 9 → 10 taken 4 times.
✓ Branch 9 → 31 taken 926 times.
930 if (detected != m_systemDistributor) {
206
8/12
✓ Branch 10 → 11 taken 4 times.
✓ Branch 14 → 15 taken 4 times.
✓ Branch 15 → 16 taken 4 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 21 taken 4 times.
✓ Branch 22 → 23 taken 4 times.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 4 times.
✓ Branch 29 → 12 taken 4 times.
✓ Branch 29 → 30 taken 4 times.
✗ Branch 139 → 140 not taken.
✗ Branch 139 → 141 not taken.
8 qCInfo(lcDavPush) << "System push service" << (detected.isEmpty() ? QStringLiteral("gone") : detected);
207 4 m_systemDistributor = detected;
208 }
209
1/1
✓ Branch 31 → 32 taken 930 times.
930 const QString paused = pauseReason();
210
1/1
✓ Branch 32 → 33 taken 930 times.
930 const auto receiver = effectiveReceiver();
211
1/1
✓ Branch 33 → 34 taken 930 times.
930 const QHash<QString, QString> labels = accountLabels();
212 // Accounts that were removed: drop their push state (their credentials are
213 // gone too; server-side expiry ends the registrations).
214
5/5
✓ Branch 34 → 35 taken 930 times.
✓ Branch 35 → 36 taken 930 times.
✓ Branch 36 → 37 taken 930 times.
✓ Branch 53 → 38 taken 68 times.
✓ Branch 53 → 54 taken 930 times.
998 for (const QString &id : m_accounts.keys()) {
215
2/2
✓ Branch 40 → 41 taken 67 times.
✓ Branch 40 → 42 taken 1 time.
68 if (labels.contains(id)) continue;
216
2/3
✓ Branch 42 → 43 taken 1 time.
✓ Branch 44 → 45 taken 1 time.
✗ Branch 44 → 49 not taken.
1 if (auto account = m_accounts.take(id)) {
217
1/1
✓ Branch 46 → 47 taken 1 time.
1 account->forget();
218
1/1
✓ Branch 48 → 49 taken 1 time.
1 account->deleteLater();
219 1 }
220
1/1
✓ Branch 50 → 51 taken 1 time.
1 DavPushSettings::forgetAccount(id);
221 930 }
222
5/5
✓ Branch 55 → 56 taken 930 times.
✓ Branch 56 → 57 taken 930 times.
✓ Branch 57 → 58 taken 930 times.
✓ Branch 127 → 59 taken 252 times.
✓ Branch 127 → 128 taken 930 times.
1182 for (const QString &id : labels.keys()) {
223
1/1
✓ Branch 60 → 61 taken 252 times.
252 const auto config = CalendarSyncCoordinator::syncConfiguration(id);
224
2/2
✓ Branch 62 → 63 taken 3 times.
✓ Branch 62 → 70 taken 249 times.
252 if (!config) {
225 // S106-075: an account whose configuration no longer resolves keeps no
226 // stream and no renewals (it kept its last target and renewed stale
227 // subscriptions forever).
228
3/3
✓ Branch 65 → 66 taken 1 time.
✓ Branch 65 → 68 taken 2 times.
✓ Branch 67 → 68 taken 1 time.
3 if (auto account = m_accounts.value(id)) account->pause();
229 3 continue;
230 3 }
231 249 DavPushAccount::Target target;
232 249 target.account = *config;
233 249 target.receiver = receiver;
234 249 target.active = paused.isEmpty();
235
1/1
✓ Branch 75 → 76 taken 249 times.
249 target.knownPaths = selectedPaths(id);
236
2/2
✓ Branch 98 → 81 taken 353 times.
✓ Branch 98 → 99 taken 249 times.
602 for (const QString &path : std::as_const(target.knownPaths)) {
237
1/1
✓ Branch 83 → 84 taken 353 times.
353 const auto record = m_store->collection(id, path);
238
6/6
✓ Branch 85 → 86 taken 178 times.
✓ Branch 85 → 91 taken 175 times.
✓ Branch 87 → 88 taken 121 times.
✓ Branch 87 → 91 taken 57 times.
✓ Branch 92 → 93 taken 114 times.
✓ Branch 92 → 95 taken 239 times.
474 if (record && record->offer.capability == DavPushCapability::Supported &&
239
3/3
✓ Branch 88 → 89 taken 121 times.
✓ Branch 89 → 90 taken 114 times.
✓ Branch 89 → 91 taken 7 times.
121 DavPushSettings::policy(id, path) == DavPushPolicy::Automatic)
240
1/1
✓ Branch 93 → 94 taken 114 times.
114 target.desiredPaths.insert(path);
241 353 }
242
9/13
✓ Branch 100 → 101 taken 83 times.
✓ Branch 100 → 108 taken 166 times.
✓ Branch 102 → 103 taken 83 times.
✓ Branch 104 → 105 taken 83 times.
✗ Branch 104 → 108 not taken.
✓ Branch 106 → 107 taken 83 times.
✗ Branch 106 → 108 not taken.
✓ Branch 109 → 110 taken 83 times.
✓ Branch 109 → 111 taken 166 times.
✓ Branch 111 → 112 taken 83 times.
✓ Branch 111 → 113 taken 166 times.
✗ Branch 164 → 165 not taken.
✗ Branch 164 → 166 not taken.
249 if (target.knownPaths.isEmpty() && m_store->collections(id).isEmpty() && !m_accounts.contains(id)) continue;
243
2/2
✓ Branch 113 → 114 taken 166 times.
✓ Branch 114 → 115 taken 166 times.
166 accountFor(id)->apply(target);
244 1265 }
245
1/1
✓ Branch 129 → 130 taken 930 times.
930 emit changed();
246 930 }
247
248 36 void DavPushCoordinator::onDiscovered(DavPushSource *source, const QString &accountId,
249 const QList<DavPushDiscovery> &found) {
250 36 QSet<QString> selected;
251
6/6
✓ Branch 3 → 4 taken 36 times.
✓ Branch 4 → 5 taken 36 times.
✓ Branch 5 → 6 taken 36 times.
✓ Branch 8 → 9 taken 104 times.
✓ Branch 11 → 7 taken 104 times.
✓ Branch 11 → 12 taken 36 times.
140 for (const auto &collection : source->collections(accountId)) selected.insert(collection.path);
252
1/1
✓ Branch 13 → 14 taken 36 times.
36 const qint64 now = m_deps.now();
253
2/2
✓ Branch 79 → 16 taken 104 times.
✓ Branch 79 → 80 taken 36 times.
140 for (const auto &discovery : found) {
254
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 104 times.
104 if (!selected.contains(discovery.path)) continue;
255
1/1
✓ Branch 21 → 22 taken 104 times.
104 auto record = m_store->collection(accountId, discovery.path).value_or(DavPushCollectionRecord{});
256 104 record.accountId = accountId;
257 104 record.path = discovery.path;
258 104 const DavPushOffer previous = record.offer;
259 // A probe error is no negative result: a known capability stays.
260
1/4
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 31 taken 104 times.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
104 if (discovery.offer.capability == DavPushCapability::ProbeError && previous.capability != DavPushCapability::Unknown) {
261 ✗ record.offer.reason = discovery.offer.reason;
262 } else {
263 104 record.offer = discovery.offer;
264 104 record.checkedAt = now;
265 }
266 // A new VAPID key invalidates the restricted subscription: register again.
267
6/6
✓ Branch 34 → 35 taken 14 times.
✓ Branch 34 → 40 taken 90 times.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 36 → 40 taken 13 times.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 58 taken 103 times.
105 if (!record.registrationUrl.isEmpty() && !previous.vapidPublicKey.isEmpty() &&
268
1/2
✓ Branch 38 → 39 taken 1 time.
✗ Branch 38 → 40 not taken.
1 previous.vapidPublicKey != record.offer.vapidPublicKey) {
269
7/7
✓ Branch 42 → 43 taken 1 time.
✓ Branch 46 → 47 taken 1 time.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 48 → 49 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
✓ Branch 53 → 44 taken 1 time.
✓ Branch 53 → 54 taken 1 time.
2 qCInfo(lcDavPush) << "VAPID key changed for" << accountId << discovery.path;
270
1/1
✓ Branch 55 → 56 taken 1 time.
1 m_store->queueCleanup(accountId, record.registrationUrl, now);
271 1 record.registrationUrl.clear();
272 1 record.expiresAt = 0;
273 }
274
2/2
✓ Branch 58 → 59 taken 83 times.
✓ Branch 58 → 71 taken 21 times.
104 if (previous.capability != record.offer.capability)
275
2/2
✓ Branch 64 → 65 taken 83 times.
✓ Branch 65 → 66 taken 83 times.
166 m_stats->event(DavPushStatistics::collectionScope(accountId, discovery.path), QStringLiteral("capability"),
276
1/1
✓ Branch 60 → 61 taken 83 times.
166 davPushCapabilityName(record.offer.capability));
277
1/1
✓ Branch 72 → 73 taken 104 times.
104 m_store->saveCollection(record);
278 104 }
279 // Collections no source selects any more and without registration are
280 // forgotten (other kinds' collections stay).
281
1/1
✓ Branch 80 → 81 taken 36 times.
36 const QSet<QString> anySelected = selectedPaths(accountId);
282
5/5
✓ Branch 82 → 83 taken 36 times.
✓ Branch 83 → 84 taken 36 times.
✓ Branch 84 → 85 taken 36 times.
✓ Branch 98 → 86 taken 109 times.
✓ Branch 98 → 99 taken 36 times.
145 for (const auto &record : m_store->collections(accountId))
283
2/6
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 92 taken 109 times.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 96 taken 109 times.
109 if (!anySelected.contains(record.path) && record.registrationUrl.isEmpty())
284
0/1
✗ Branch 95 → 96 not taken.
36 m_store->removeCollection(accountId, record.path);
285
1/1
✓ Branch 100 → 101 taken 36 times.
36 reconfigure();
286 36 }
287
288 85 void DavPushCoordinator::onBatchStarted(const QString &accountId, const QStringList &forcedPaths) {
289 85 auto account = m_accounts.value(accountId);
290
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 84 times.
85 if (!account) return;
291
2/2
✓ Branch 26 → 8 taken 53 times.
✓ Branch 26 → 27 taken 84 times.
137 for (const QString &path : forcedPaths)
292
2/3
✓ Branch 10 → 11 taken 53 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 24 taken 53 times.
53 if (const auto since = account->pendingPushSince(path))
293 ✗ m_stats->latency(DavPushStatistics::collectionScope(accountId, path), QStringLiteral("push-start"), *since);
294 85 }
295
296 68 void DavPushCoordinator::onSyncFinished(const DavPushSyncReport &result) {
297
1/1
✓ Branch 2 → 3 taken 68 times.
68 const QString reason = primaryReason(result.reasons);
298
3/3
✓ Branch 7 → 8 taken 68 times.
✓ Branch 8 → 9 taken 68 times.
✓ Branch 9 → 10 taken 68 times.
136 m_stats->count(DavPushStatistics::accountScope(result.accountId), QStringLiteral("batches.") + reason);
299 68 auto account = m_accounts.value(result.accountId);
300
1/1
✓ Branch 15 → 16 taken 68 times.
68 const qint64 now = m_deps.now();
301
2/2
✓ Branch 58 → 18 taken 138 times.
✓ Branch 58 → 59 taken 68 times.
206 for (const QString &path : result.syncedPaths) {
302
1/1
✓ Branch 19 → 20 taken 138 times.
138 const QString scope = DavPushStatistics::collectionScope(result.accountId, path);
303
2/2
✓ Branch 24 → 25 taken 138 times.
✓ Branch 25 → 26 taken 138 times.
276 m_stats->count(scope, QStringLiteral("syncs.") + reason);
304
2/3
✓ Branch 30 → 31 taken 138 times.
✓ Branch 32 → 33 taken 138 times.
✗ Branch 32 → 37 not taken.
138 if (auto record = m_store->collection(result.accountId, path)) {
305 138 record->lastSyncAt = now;
306
1/1
✓ Branch 36 → 37 taken 138 times.
138 m_store->saveCollection(*record);
307 138 }
308
1/2
✓ Branch 39 → 40 taken 138 times.
✗ Branch 39 → 55 not taken.
138 if (account) {
309
3/3
✓ Branch 41 → 42 taken 138 times.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 54 taken 137 times.
138 if (const auto since = account->pendingPushSince(path)) {
310
1/1
✓ Branch 49 → 50 taken 1 time.
2 m_stats->latency(scope, QStringLiteral("push-commit"), *since);
311
1/1
✓ Branch 53 → 54 taken 1 time.
1 account->clearPendingPush(path);
312 }
313 }
314 138 }
315
1/2
✗ Branch 73 → 61 not taken.
✓ Branch 73 → 74 taken 68 times.
68 for (const QString &path : result.failedPaths)
316 ✗ m_stats->count(DavPushStatistics::collectionScope(result.accountId, path), QStringLiteral("syncs.failed"));
317
1/1
✓ Branch 74 → 75 taken 68 times.
68 emit changed();
318 68 }
319
320 10 void DavPushCoordinator::onPushHealth(const QString &accountId, bool failing) {
321
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 37 taken 2 times.
10 if (failing) {
322 8 bool entered = false;
323
7/7
✓ Branch 6 → 7 taken 8 times.
✓ Branch 6 → 10 taken 1 time.
✓ Branch 8 → 9 taken 8 times.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 11 taken 3 times.
✓ Branch 14 → 5 taken 9 times.
✓ Branch 14 → 15 taken 8 times.
17 for (const auto &source : m_deps.sources) entered = entered || !source->inFallback(accountId);
324
2/2
✓ Branch 15 → 16 taken 5 times.
✓ Branch 15 → 37 taken 3 times.
8 if (entered) {
325
2/2
✓ Branch 20 → 21 taken 5 times.
✓ Branch 21 → 22 taken 5 times.
10 m_stats->count(DavPushStatistics::accountScope(accountId), QStringLiteral("fallback.entered"));
326
2/2
✓ Branch 30 → 31 taken 5 times.
✓ Branch 31 → 32 taken 5 times.
10 m_stats->event(DavPushStatistics::accountScope(accountId), QStringLiteral("fallback"));
327 }
328 }
329
3/3
✓ Branch 41 → 42 taken 12 times.
✓ Branch 44 → 39 taken 12 times.
✓ Branch 44 → 45 taken 10 times.
22 for (const auto &source : m_deps.sources) source->setFallback(accountId, failing);
330 10 emit changed();
331 10 }
332
333 6 void DavPushCoordinator::setPolicy(const QString &accountId, const QString &path, DavPushPolicy policy) {
334 6 DavPushSettings::setPolicy(accountId, path, policy);
335
2/2
✓ Branch 14 → 15 taken 6 times.
✓ Branch 15 → 16 taken 6 times.
12 m_stats->event(DavPushStatistics::collectionScope(accountId, path), QStringLiteral("policy"),
336
6/10
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 8 taken 5 times.
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 5 times.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
18 policy == DavPushPolicy::Automatic ? QStringLiteral("automatic") : QStringLiteral("interval"));
337 6 reconfigure();
338 6 }
339
340 1 void DavPushCoordinator::reconnect(const QString &accountId) {
341
2/3
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
1 if (auto account = m_accounts.value(accountId)) account->reconnect();
342
1/1
✓ Branch 9 → 10 taken 1 time.
1 requestSync(accountId, {}, DavSyncReasonManual);
343 1 }
344
345 1 void DavPushCoordinator::detectAgain(const QString &accountId) {
346
1/1
✓ Branch 3 → 4 taken 1 time.
1 requestSync(accountId, {}, DavSyncReasonManual);
347 1 }
348
349 1 void DavPushCoordinator::syncCollectionNow(const QString &accountId, const QString &path) {
350
3/5
✓ Branch 4 → 5 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 1 time.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
2 requestSync(accountId, {path}, DavSyncReasonManual);
351 2 }
352
353 2 bool DavPushCoordinator::resetStatistics(const QString &accountId, const QString &path) {
354
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1 time.
2 if (!m_stats) return false;
355
3/5
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
2 return m_stats->reset(path.isEmpty() ? DavPushStatistics::accountScope(accountId)
356 1 : DavPushStatistics::collectionScope(accountId, path));
357 }
358
359 5 void DavPushCoordinator::storeProviderToken(const QByteArray &token, std::function<void(bool)> done) {
360
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 18 taken 4 times.
5 if (!isOpen()) {
361
5/5
✓ Branch 4 → 5 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 13 → 6 taken 1 time.
✓ Branch 13 → 14 taken 1 time.
2 qCWarning(lcDavPush) << "Cannot store the push service token: push storage is not open";
362
1/2
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 1 time.
1 if (done) done(false);
363 1 return;
364 }
365
3/3
✓ Branch 21 → 22 taken 4 times.
✓ Branch 22 → 23 taken 4 times.
✓ Branch 23 → 24 taken 4 times.
8 m_deps.secrets->write(this, DavPushSecretKeys::providerToken(m_installationId), token,
366 8 [this, done = std::move(done)](bool ok) {
367
7/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 14 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 12 → 5 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
3 if (!ok) qCWarning(lcDavPush) << "Cannot store the push service token";
368
2/2
✓ Branch 24 → 17 taken 1 time.
✓ Branch 24 → 25 taken 2 times.
3 for (const auto &account : std::as_const(m_accounts))
369
2/3
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 22 not taken.
✓ Branch 21 → 22 taken 1 time.
1 if (account) account->reloadToken();
370 2 reconfigure();
371
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 1 time.
2 if (done) done(ok);
372 2 });
373 }
374
375 1 void DavPushCoordinator::removeProviderToken() {
376
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!isOpen()) return;
377
2/2
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
1 m_deps.secrets->remove(this, DavPushSecretKeys::providerToken(m_installationId), [](bool ok) {
378 ✗ qCInfo(lcDavPush) << "Push service token removed:" << ok;
379 ✗ });
380 }
381
382 1093 QList<DavPushCollectionStatus> DavPushCoordinator::statuses() const {
383 1093 QList<DavPushCollectionStatus> result;
384
3/3
✓ Branch 2 → 3 taken 1093 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 1092 times.
1093 if (!isOpen()) return result;
385
1/1
✓ Branch 5 → 6 taken 1092 times.
1092 const QString paused = pauseReason();
386
1/1
✓ Branch 6 → 7 taken 1092 times.
1092 const bool receiverConfigured = effectiveReceiver().isConfigured();
387
1/1
✓ Branch 9 → 10 taken 1092 times.
1092 const QHash<QString, QString> labels = accountLabels();
388
1/1
✓ Branch 10 → 11 taken 1092 times.
1092 const qint64 now = m_deps.now();
389
2/2
✓ Branch 141 → 13 taken 2032 times.
✓ Branch 141 → 142 taken 1092 times.
3124 for (const auto &source : m_deps.sources)
390
2/2
✓ Branch 138 → 15 taken 597 times.
✓ Branch 138 → 139 taken 2032 times.
2629 for (auto it = labels.cbegin(); it != labels.cend(); ++it) {
391 597 const DavPushAccount *account = m_accounts.value(it.key());
392
5/5
✓ Branch 21 → 22 taken 597 times.
✓ Branch 22 → 23 taken 597 times.
✓ Branch 23 → 24 taken 597 times.
✓ Branch 133 → 25 taken 583 times.
✓ Branch 133 → 134 taken 597 times.
1180 for (const auto &collection : source->collections(it.key())) {
393 583 const QString &path = collection.path;
394 583 DavPushCollectionStatus status;
395 583 status.accountId = it.key();
396 583 status.path = path;
397
1/1
✓ Branch 30 → 31 taken 583 times.
583 status.kind = source->kind();
398
1/1
✓ Branch 34 → 35 taken 583 times.
583 status.intervalMinutes = source->intervalMinutes();
399 583 status.accountLabel = it.value();
400 583 status.displayName = collection.displayName;
401 583 status.readOnly = collection.readOnly;
402
1/1
✓ Branch 39 → 40 taken 583 times.
583 status.policy = DavPushSettings::policy(it.key(), path);
403 583 status.pauseReason = paused;
404
1/1
✓ Branch 43 → 44 taken 583 times.
583 status.inFallback = source->inFallback(it.key());
405
1/1
✓ Branch 46 → 47 taken 583 times.
583 status.syncRunning = source->syncRunning(it.key());
406
3/3
✓ Branch 49 → 50 taken 583 times.
✓ Branch 51 → 52 taken 463 times.
✓ Branch 51 → 93 taken 120 times.
583 if (const auto record = m_store->collection(it.key(), path)) {
407 463 status.offer = record->offer;
408 463 status.checkedAt = record->checkedAt;
409 463 status.expiresAt = record->expiresAt;
410 463 status.registrationError = record->lastError;
411 463 status.nextRetryAt = record->nextRetryAt;
412 463 status.lastPushAt = record->lastPushAt;
413 463 status.lastSyncAt = record->lastSyncAt;
414
6/7
✓ Branch 61 → 62 taken 463 times.
✗ Branch 61 → 65 not taken.
✓ Branch 62 → 63 taken 463 times.
✓ Branch 63 → 64 taken 44 times.
✓ Branch 63 → 65 taken 419 times.
✓ Branch 66 → 67 taken 44 times.
✓ Branch 66 → 68 taken 419 times.
463 if (account && account->registering(path)) status.registration = DavPushRegistrationState::Registering;
415
6/7
✓ Branch 68 → 69 taken 419 times.
✗ Branch 68 → 72 not taken.
✓ Branch 69 → 70 taken 419 times.
✓ Branch 70 → 71 taken 3 times.
✓ Branch 70 → 72 taken 416 times.
✓ Branch 73 → 74 taken 3 times.
✓ Branch 73 → 75 taken 416 times.
419 else if (account && account->unregistering(path)) status.registration = DavPushRegistrationState::Removing;
416
5/6
✓ Branch 77 → 78 taken 211 times.
✓ Branch 77 → 81 taken 205 times.
✓ Branch 79 → 80 taken 211 times.
✗ Branch 79 → 81 not taken.
✓ Branch 82 → 83 taken 211 times.
✓ Branch 82 → 84 taken 205 times.
416 else if (!record->registrationUrl.isEmpty() && record->expiresAt > now)
417 211 status.registration = DavPushRegistrationState::Active;
418
5/6
✓ Branch 86 → 87 taken 30 times.
✓ Branch 86 → 90 taken 175 times.
✓ Branch 88 → 89 taken 30 times.
✗ Branch 88 → 90 not taken.
✓ Branch 91 → 92 taken 30 times.
✓ Branch 91 → 93 taken 175 times.
205 else if (!record->lastError.isEmpty() && record->nextRetryAt > 0)
419 30 status.registration = DavPushRegistrationState::Failed;
420 583 }
421
2/2
✓ Branch 94 → 95 taken 99 times.
✓ Branch 94 → 96 taken 484 times.
583 if (!receiverConfigured) {
422 99 status.receiver = DavPushReceiverState::NotConfigured;
423
5/6
✓ Branch 96 → 97 taken 484 times.
✗ Branch 96 → 100 not taken.
✓ Branch 98 → 99 taken 439 times.
✓ Branch 98 → 100 taken 45 times.
✓ Branch 101 → 102 taken 439 times.
✓ Branch 101 → 115 taken 45 times.
484 } else if (account && account->receiver()) {
424 439 status.receiver = account->receiver()->state();
425 439 status.receiverDetail = account->receiver()->failureDetail();
426 439 status.receiverConnectedSince = account->receiver()->connectedSince();
427 439 status.receiverLastActivity = account->receiver()->lastActivity();
428 439 status.receiverNextAttempt = account->receiver()->nextAttemptAt();
429
6/8
✓ Branch 115 → 116 taken 45 times.
✗ Branch 115 → 120 not taken.
✓ Branch 118 → 119 taken 12 times.
✓ Branch 118 → 120 taken 33 times.
✓ Branch 121 → 122 taken 45 times.
✗ Branch 121 → 123 not taken.
✓ Branch 123 → 124 taken 12 times.
✓ Branch 123 → 128 taken 33 times.
45 } else if (account && !account->receiverProblem().isEmpty()) {
430 12 status.receiver = DavPushReceiverState::Failed;
431 12 status.receiverDetail = account->receiverProblem();
432 } else {
433 33 status.receiver = DavPushReceiverState::Stopped;
434 }
435
1/1
✓ Branch 129 → 130 taken 583 times.
583 result.append(status);
436 1180 }
437 }
438 1092 return result;
439 1092 }
440
441 4 QString DavPushCoordinator::diagnosticsReport() const {
442 4 return davPushDiagnosticsReport(*this);
443 }
444