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: 100.0% 1 / 0 / 1
Functions: 100.0% 1 / 0 / 1
Branches: 100.0% 1 / 0 / 1

presentation/RuleSuggestions.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QDateTime>
4 #include <QHash>
5 #include <QSet>
6 #include <QString>
7
8 #include <optional>
9
10 // Rule suggestions from manual moves (Sprint 95 S95.4.5, D-12, RJ5).
11 //
12 // Counts manual moves per (sender address, target folder) of one account;
13 // mailing-list mail is counted per "list:<List-Id>" instead of its sender.
14 // The third move of the same pair within 30 days yields one suggestion;
15 // a pair is offered once, and "Not for this sender" silences the sender
16 // for good. Rule moves (apply to existing) are not recorded by the caller.
17 // State lives in a small JSON file next to the account's rule data
18 // (<profile>/sieve/<account-id>/suggestions.json, 0600); the predictor's
19 // training data is not touched.
20 //
21 // Invariants:
22 // - Addresses are compared lower case; folders as given (raw IMAP path).
23 // - At most kMaxPairs pairs are kept; the oldest are dropped first.
24 // - A malformed file is treated as empty and rewritten on the next change.
25 class RuleSuggestions {
26 public:
27 static constexpr int kThreshold = 3;
28 static constexpr int kWindowDays = 30;
29 static constexpr int kMaxPairs = 500;
30
31 struct Suggestion {
32 QString sender;
33 QString folder;
34 int count = 0;
35 };
36
37 void setFile(const QString &path); // loads; empty path = memory only
38 QString file() const { return m_file; }
39
40 // Records one move; returns a suggestion when the pair reaches the
41 // threshold and was neither offered nor silenced.
42 std::optional<Suggestion> record(const QString &sender, const QString &folder, const QDateTime &now);
43 void markOffered(const QString &sender, const QString &folder);
44 void silenceSender(const QString &sender);
45
1/1
✓ Branch 2 → 3 taken 7 times.
7 bool silenced(const QString &sender) const { return m_silenced.contains(sender.toLower()); }
46 int count(const QString &sender, const QString &folder) const;
47
48 private:
49 struct Pair {
50 int count = 0;
51 QDateTime first;
52 QDateTime last;
53 bool offered = false;
54 };
55 static QString key(const QString &sender, const QString &folder);
56 void load();
57 void save() const;
58 void prune(const QDateTime &now);
59
60 QString m_file;
61 QHash<QString, Pair> m_pairs; // "sender\nfolder"
62 QSet<QString> m_silenced;
63 };
64