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% 6 / 0 / 6
Functions: 100.0% 4 / 0 / 4
Branches: 80.0% 4 / 0 / 5

data/RecurrenceRule.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QDateTime>
4 #include <QList>
5 #include <QString>
6 #include <QStringList>
7
8 // RFC 5545 §3.3.10 recurrence rules (Sprint 93 S93.1.4, CAL-RRULE).
9 //
10 // parse()/toString() round-trip every rule part; unknown parts are kept in
11 // `unknownParts` so a rule MailJD cannot fully interpret is never rewritten
12 // (the editor keeps it, S93.1.5). expandNaive() iterates occurrences on
13 // wall-clock times: the caller converts its DTSTART into the event's zone,
14 // expands, and converts every result back (RecurrenceExpansion.cpp). That
15 // keeps a 10:00 series at 10:00 across DST changes (S93.1.3).
16 struct RecurrenceRule {
17 enum class Frequency { None, Secondly, Minutely, Hourly, Daily, Weekly, Monthly, Yearly };
18 struct WeekdayNum {
19 813 int ordinal = 0; // 0 = every such weekday; +n/-n = nth/nth-last in month or year
20 810 int weekday = 1; // ISO: 1 = Monday … 7 = Sunday
21
3/4
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 810 times.
✓ Branch 4 → 5 taken 810 times.
✗ Branch 4 → 6 not taken.
813 bool operator==(const WeekdayNum &) const = default;
22 };
23
24 Frequency frequency = Frequency::None;
25 int interval = 1;
26 int count = 0; // 0 = unbounded
27 QString until; // wire form (yyyyMMdd or yyyyMMddTHHmmss[Z]); empty = none
28 QList<int> bySecond, byMinute, byHour;
29 QList<WeekdayNum> byDay;
30 QList<int> byMonthDay, byYearDay, byWeekNo, byMonth, bySetPos;
31 int weekStart = 1; // WKST, ISO weekday
32 bool weekStartGiven = false;
33 QStringList unknownParts; // "KEY=VALUE" parts MailJD does not interpret
34 bool valid = false;
35 QString error; // parse error when !valid
36
37 static RecurrenceRule parse(const QString &text);
38 // Canonical serialization (FREQ first). Unknown parts are appended as-is.
39 QString toString() const;
40 // True when every part is interpreted by expandNaive().
41 bool fullySupported() const;
42 2831 bool hasUntil() const { return !until.isEmpty(); }
43 358 bool untilIsDate() const { return until.size() == 8; }
44
1/1
✓ Branch 4 → 5 taken 82 times.
82 bool untilIsUtc() const { return until.endsWith(QLatin1Char('Z')); }
45 // UNTIL as a naive wall-clock stamp (Qt::UTC used as "no zone"); date-only
46 // values end at the given time of day.
47 QDateTime untilNaive(const QTime &dateOnlyTime) const;
48
49 static QString frequencyName(Frequency frequency);
50 static Frequency frequencyFromName(const QString &name);
51 static QString weekdayToken(int isoWeekday);
52 static int weekdayFromToken(const QString &token);
53 };
54
55 // Result of a naive expansion. All QDateTime values are wall-clock stamps
56 // carried in Qt::UTC (no zone arithmetic happens inside the engine).
57 struct NaiveExpansion {
58 QList<QDateTime> starts; // ascending, DTSTART first when inside the window
59 bool partial = false; // the rule could not be expanded completely
60 bool truncated = false; // the iteration cap stopped the expansion
61 bool limited = false; // `maxStarts` was reached and more starts exist (Sprint 102)
62 };
63
64 // Expands `rule` from `start` (always the first occurrence, RFC 5545
65 // §3.3.10: "DTSTART ... counts as the first occurrence"). Only occurrences
66 // in [windowStart, windowEnd] are returned, but COUNT counts every one.
67 // `until` (naive) bounds the series; invalid = no UNTIL. Unsupported rules
68 // return only `start` with partial = true. `maxStarts` > 0 stops after that
69 // many starts at or after `countFrom` (starts before it, a display margin,
70 // do not count) and sets `limited` when another one exists.
71 NaiveExpansion expandNaive(const RecurrenceRule &rule, const QDateTime &start,
72 const QDateTime &windowStart, const QDateTime &windowEnd,
73 const QDateTime &until = {}, qsizetype maxStarts = 0,
74 const QDateTime &countFrom = {});
75
76 // Human description in the current UI language, e.g. "Every 2 weeks on
77 // Monday and Wednesday, until 31 Dec 2026". `start` supplies the implicit
78 // day/weekday/month of rules without BY parts. Empty for an invalid rule.
79 QString describeRecurrence(const RecurrenceRule &rule, const QDateTime &start);
80