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: 79.1% 53 / 0 / 67
Functions: 100.0% 5 / 0 / 5
Branches: 54.2% 71 / 0 / 131

app/core/CalendarOutboxRefused.cpp
Line Branch Exec Source
1 // F108-12 (Sprint 108 user review): writes the server refuses. Nextcloud
2 // answers 404 to a PUT it refuses in a calendar shared with the user while
3 // a GET still returns the item; that is confirmed before it counts as
4 // "deleted on the server" (a conflict), and an item the server still has is
5 // a refused write: bounded retries, then "failed" — with the user's ways out
6 // (try again now, or drop the local change for the server's version).
7 #include "CalendarOutbox.h"
8
9 #include "data/CalendarStore.h"
10 #include "service/CalDavClient.h"
11
12 #include <QLoggingCategory>
13
14 Q_DECLARE_LOGGING_CATEGORY(lcCalendarOutbox)
15
16 8 void CalendarOutbox::confirmDeletedOnServer(const CalendarOutboxEntry &entry, const QString &url,
17 const Endpoint &endpoint) {
18 8 CalDavClient *client = clientFor(endpoint);
19 8 const quint64 request = client->getResource(url);
20
1/1
✓ Branch 5 → 6 taken 8 times.
8 connect(client, &CalDavClient::resourceResponse, this, [this, request, entry](const DavResponse &response) {
21
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8 times.
8 if (response.request != request)
22 ✗ return;
23
3/4
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 6 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 21 taken 2 times.
8 if (response.status == 404 || response.status == 410) {
24
3/5
✓ Branch 12 → 13 taken 6 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 19 taken 6 times.
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 65 not taken.
12 markConflict(entry, QString(), QString(), {QStringLiteral("deleted")});
25 6 return;
26 }
27
1/2
✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 38 not taken.
2 if (response.status == 200) {
28 // The server still has it: not a deletion to ask about, but a write
29 // it refuses here — bounded retries, then the visible "failed" state.
30
7/7
✓ Branch 22 → 23 taken 2 times.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 27 → 28 taken 2 times.
✓ Branch 28 → 29 taken 2 times.
✓ Branch 29 → 30 taken 2 times.
✓ Branch 33 → 24 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
4 qCWarning(lcCalendarOutbox) << "The server refuses writing" << entry.uid << "(404 on PUT, 200 on GET)";
31
2/2
✓ Branch 34 → 35 taken 2 times.
✓ Branch 35 → 36 taken 2 times.
2 retryLater(entry, tr("The server refuses changes to this item here (it still has it)."), true);
32 2 return;
33 }
34 // Neither answer (the network, a server error): try the write again later.
35 ✗ retryLater(entry, response.error.isEmpty() ? QStringLiteral("HTTP %1").arg(response.status) : response.error, false);
36
1/5
✓ Branch 9 → 10 taken 6 times.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 73 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
12 });
37 8 }
38
39 1 bool CalendarOutbox::retryWrite(const QString &uid, const QString &accountId, const QString &calendarPath) {
40 1 CalendarStore *store = m_deps.store;
41
1/1
✓ Branch 2 → 3 taken 1 time.
1 auto entry = store->outboxEntry(accountId, calendarPath, uid);
42
3/6
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
1 if (!entry || entry->state == QLatin1String("conflict"))
43 ✗ return false;
44 1 entry->state = QStringLiteral("pending");
45 1 entry->attempts = 0;
46 1 entry->nextAttempt = 0;
47
1/1
✓ Branch 23 → 24 taken 1 time.
1 store->updateOutbox(*entry);
48
7/7
✓ Branch 24 → 25 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 35 → 26 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
2 qCInfo(lcCalendarOutbox) << "Retrying the write of" << uid << "now";
49
1/1
✓ Branch 36 → 37 taken 1 time.
1 publishChange();
50
1/1
✓ Branch 37 → 38 taken 1 time.
1 requestFlush();
51 1 return true;
52 1 }
53
54 1 bool CalendarOutbox::discardLocalChange(const QString &uid, const QString &accountId, const QString &calendarPath) {
55 1 CalendarStore *store = m_deps.store;
56
1/1
✓ Branch 2 → 3 taken 1 time.
1 const auto entry = store->outboxEntry(accountId, calendarPath, uid);
57
6/13
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 12 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 12 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 16 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 62 not taken.
1 if (!entry || entry->state == QLatin1String("conflict") || m_inFlight.contains(key(accountId, calendarPath, uid)))
58 ✗ return false;
59
4/7
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 23 not taken.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1 time.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 1 time.
1 if (m_deps.networkAllowed && !m_deps.networkAllowed())
60 ✗ return false;
61
1/1
✓ Branch 26 → 27 taken 1 time.
1 const auto endpoint = m_deps.endpoint(accountId);
62
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 1 time.
1 if (!endpoint)
63 ✗ return false;
64
1/1
✓ Branch 31 → 32 taken 1 time.
1 CalDavClient *client = clientFor(*endpoint);
65
1/1
✓ Branch 33 → 34 taken 1 time.
1 const QString url = client->eventResourceUrl(entry->href, calendarPath, uid);
66
2/2
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
1 m_inFlight.insert(key(accountId, calendarPath, uid));
67
1/1
✓ Branch 37 → 38 taken 1 time.
1 const quint64 request = client->getResource(url);
68
7/7
✓ Branch 38 → 39 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
✓ Branch 49 → 40 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
2 qCInfo(lcCalendarOutbox) << "Discarding the local change of" << uid << "- fetching the server version";
69
1/1
✓ Branch 52 → 53 taken 1 time.
1 connect(client, &CalDavClient::resourceResponse, this, [this, request, entry = *entry](const DavResponse &response) {
70
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 if (response.request != request)
71 1 return;
72 1 CalendarStore *store = m_deps.store;
73
1/1
✓ Branch 4 → 5 taken 1 time.
1 finishInFlight(entry);
74
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
1 const QString local = QString::fromUtf8(localBody(entry));
75
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 23 not taken.
1 if (response.status == 200) {
76
1/1
✓ Branch 12 → 13 taken 1 time.
2 recordHistory(entry, QStringLiteral("server"), local);
77
3/4
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 41 not taken.
1 if (adoptServerVersion(entry, QString::fromUtf8(response.body), response.etag)) {
78
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
1 emit statusMessage(tr("Your change was dropped; the server's version is back."));
79 1 return;
80 }
81 ✗ } else if (response.status == 404 || response.status == 410) {
82 ✗ recordHistory(entry, QStringLiteral("server"), local);
83 ✗ if (adoptServerVersion(entry, QString(), QString())) {
84 ✗ emit statusMessage(tr("Your change was dropped; the server no longer has this item."));
85 ✗ return;
86 }
87 }
88 ✗ qCWarning(lcCalendarOutbox) << "Could not drop the local change of" << entry.uid << "status" << response.status;
89 ✗ store->updateOutbox(entry);
90 ✗ emit statusMessage(tr("The server's version could not be fetched. Try again later."));
91
1/2
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 63 taken 1 time.
1 });
92 1 return true;
93 1 }
94