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.3% 12 / 0 / 13
Functions: 90.9% 10 / 0 / 11
Branches: 40.0% 4 / 0 / 10

presentation/DavCollectionDiscovery.h
Line Branch Exec Source
1 #pragma once
2 #include "DavAccountSettings.h"
3 #include "data/DavCredentials.h"
4 #include <QAbstractListModel>
5 #include <QPointer>
6 #include <functional>
7
8 class CalDavClient;
9 class CardDavClient;
10
11 // A settings-owned discovery operation. Enumeration never changes selections;
12 // only an explicit apply writes the captured account's current configuration.
13 class DavCollectionDiscovery final : public QAbstractListModel {
14 15 Q_OBJECT
15 Q_PROPERTY(QString accountId READ accountId NOTIFY stateChanged)
16 Q_PROPERTY(QString accountLabel READ accountLabel NOTIFY stateChanged)
17 Q_PROPERTY(QString state READ state NOTIFY stateChanged)
18 Q_PROPERTY(QString error READ error NOTIFY stateChanged)
19 Q_PROPERTY(bool busy READ busy NOTIFY stateChanged)
20 Q_PROPERTY(bool canApply READ canApply NOTIFY stateChanged)
21 // Sprint 100 D-22: collections on the server that are not on this
22 // computer, never offered before and not dismissed ([{key, name, kind}]).
23 Q_PROPERTY(QVariantList newCollections READ newCollections NOTIFY stateChanged)
24 // S106-459: the number of rows (the filter and empty-state gates).
25 Q_PROPERTY(int count READ count NOTIFY countChanged)
26 public:
27 using Account = DavAccountSettings::Account;
28 using Resolver = std::function<void(QObject *, const Account &, DavCredentials::PasswordCallback)>;
29 using CalendarFactory = std::function<CalDavClient *(const Account &, const QByteArray &)>;
30 using BookFactory = std::function<CardDavClient *(const Account &, const QByteArray &)>;
31 // Sprint 100 S100.1.12: what each collection is (§6.2.5 row anatomy).
32 enum Role { Name = Qt::UserRole + 1, Path, Kind, Selected, Available, Color, Content, ReadOnly, Push, Reason, Key };
33 // One discovered collection (calendar or address book).
34 struct Item {
35 QString path, name, color;
36 QStringList components; // VEVENT/VTODO; empty = not restricted
37 bool readOnly = false;
38 bool push = false;
39 };
40 // Local changes not uploaded yet (outbox) of a collection (D-21 guard).
41 using PendingCounter = std::function<int(const QString &accountId, const QString &path, bool calendar)>;
42 explicit DavCollectionDiscovery(QObject *parent = nullptr);
43 ~DavCollectionDiscovery() override;
44 int rowCount(const QModelIndex &parent = {}) const override;
45 67 int count() const { return m_rows.size(); }
46 QVariant data(const QModelIndex &index, int role) const override;
47 QHash<int, QByteArray> roleNames() const override;
48 46 QString accountId() const { return m_account.id; }
49 ✗ QString accountLabel() const { return m_account.username + QStringLiteral(" · ") + m_account.serverUrl; }
50 223 QString state() const { return m_state; }
51 4 QString error() const { return m_error; }
52 130 bool busy() const { return m_busy; }
53
4/8
✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 14 times.
✓ Branch 3 → 7 taken 4 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 14 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
18 bool canApply() const { return !m_busy && m_dirty && (m_calendarsOk || m_booksOk); }
54 Q_INVOKABLE bool discover(const QString &accountId);
55 Q_INVOKABLE void cancel();
56 Q_INVOKABLE bool setSelected(int row, bool selected);
57 Q_INVOKABLE bool apply();
58 // Sprint 100 S100.1.13: one toggle applies at once (no "Save selection").
59 // Deselecting is refused while the collection has local changes that are
60 // not uploaded: {ok, pending, name, selected}.
61 Q_INVOKABLE QVariantMap toggle(int row, bool selected);
62 // Opens the last known collections of the account at once (cache) and
63 // refreshes them from the server in the background.
64 Q_INVOKABLE bool open(const QString &accountId);
65 // D-20: everything on except the server's system address book and
66 // birthday calendars (their reason is shown). Returns the selected count.
67 Q_INVOKABLE int selectDefaults();
68 Q_INVOKABLE void dismissNew(const QString &key);
69 // D-22 "Add": turns on the new collection with that key (toggle()).
70 Q_INVOKABLE QVariantMap addNew(const QString &key);
71 // S106-460: the toggle of the collection with that key (Undo of a toast
72 // keeps naming the same collection after the rows were re-read).
73 Q_INVOKABLE QVariantMap toggleKey(const QString &key, bool selected);
74 QVariantList newCollections() const;
75 // D-22: the per-account cache of the collections on the server and the
76 // keys already known (seen at the first discovery of their kind, added or
77 // dismissed). Static: the sidebar hints (DavServerHints) and every
78 // calendar sync read and write the same QSettings entries.
79 struct CachedCollection {
80 QString name, path, key, kind;
81 bool calendar = false;
82 QStringList components; // empty = not restricted (events and tasks)
83 };
84 static QString keyFor(const QString &serverUrl, const QString &path);
85 static QString kindOf(bool calendar, const QStringList &components);
86 static QList<CachedCollection> cachedCollections(const Account &account);
87 static QStringList knownKeys(const QString &accountId);
88 static void addKnown(const QString &accountId, const QStringList &keys);
89 // What a calendar sync discovered replaces the cached calendars (address
90 // books kept); the first record of calendars seeds them as known.
91 static void recordCalendars(const Account &account, const QList<Item> &calendars);
92 796 void setPendingCounter(PendingCounter counter) { m_pendingCounter = std::move(counter); }
93 // The reason a collection is off by default ("" = none, D-20).
94 static QString defaultOffReason(const QString &path, bool calendar);
95 void invalidateConfiguration();
96 18 void setResolver(Resolver resolver) { m_resolver = std::move(resolver); }
97 17 void setFactories(CalendarFactory calendars, BookFactory books) {
98 17 m_calendarFactory = std::move(calendars); m_bookFactory = std::move(books);
99 17 }
100 signals:
101 void countChanged();
102 void stateChanged();
103 void applied(const QString &accountId);
104 private:
105 struct Row {
106 QString name, path;
107 bool calendar = false, selected = false, available = true, initiallySelected = false;
108 QString color;
109 QStringList components;
110 bool readOnly = false, push = false;
111 };
112 QString contentKind(const Row &row) const;
113 bool currentConfiguration() const;
114 QString collectionKey(const QString &path) const;
115 void beginNetwork(quint64 generation, QByteArray password, const QString &error);
116 void received(bool calendars, const QList<Item> &values, const QString &error = {});
117 void writeCache() const;
118 void rememberKnown(const QStringList &keys);
119 bool readCache();
120 void completeEnumeration();
121 void fail(const QString &error);
122 void stopRequest();
123 Account m_account;
124 DavAccountSettings::CalendarConfig m_calendarConfig;
125 QList<Row> m_rows, m_calendars, m_books;
126 QString m_state = QStringLiteral("idle"), m_error;
127 QString m_calendarError, m_bookError;
128 bool m_busy = false, m_dirty = false;
129 bool m_calendarsDone = false, m_booksDone = false, m_calendarsOk = false, m_booksOk = false;
130 quint64 m_generation = 0;
131 QPointer<QObject> m_request;
132 Resolver m_resolver;
133 CalendarFactory m_calendarFactory;
134 BookFactory m_bookFactory;
135 PendingCounter m_pendingCounter;
136 QStringList m_cachedKeys; // known collections of the account (D-22)
137 };
138