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% 54 / 0 / 54
Functions: 100.0% 5 / 0 / 5
Branches: 92.2% 118 / 0 / 128

data/FreeSlots.cpp
Line Branch Exec Source
1 #include "FreeSlots.h"
2
3 #include <algorithm>
4
5 namespace FreeSlots {
6
7 23 QList<Interval> find(const QList<Interval> &busy, const Options &options) {
8 23 QList<Interval> found;
9
6/7
✓ Branch 2 → 3 taken 23 times.
✓ Branch 3 → 4 taken 23 times.
✗ Branch 3 → 7 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 22 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 22 times.
23 if (!options.from.isValid() || options.dayEnd <= options.dayStart) return found;
10
1/1
✓ Branch 11 → 12 taken 22 times.
22 const int days = std::clamp(options.days, 1, 60);
11
1/1
✓ Branch 12 → 13 taken 22 times.
22 const int duration = std::clamp(options.durationMinutes, 5, 480);
12
1/1
✓ Branch 13 → 14 taken 22 times.
22 const int step = std::clamp(options.stepMinutes, 5, 120);
13
1/1
✓ Branch 14 → 15 taken 22 times.
22 const int maximum = std::clamp(options.maximum, 1, 500);
14 // Busy intervals sorted by start; invalid or empty ones are ignored.
15 22 QList<Interval> sorted;
16
2/2
✓ Branch 31 → 17 taken 24 times.
✓ Branch 31 → 32 taken 22 times.
46 for (const Interval &interval : busy)
17
8/12
✓ Branch 18 → 19 taken 24 times.
✓ Branch 19 → 20 taken 24 times.
✗ Branch 19 → 26 not taken.
✓ Branch 20 → 21 taken 24 times.
✓ Branch 21 → 22 taken 24 times.
✗ Branch 21 → 26 not taken.
✓ Branch 22 → 23 taken 24 times.
✓ Branch 24 → 25 taken 24 times.
✗ Branch 24 → 26 not taken.
✓ Branch 27 → 28 taken 24 times.
✗ Branch 27 → 29 not taken.
✓ Branch 28 → 29 taken 24 times.
24 if (interval.start.isValid() && interval.end.isValid() && interval.end > interval.start) sorted.append(interval);
18
3/3
✓ Branch 32 → 33 taken 22 times.
✓ Branch 33 → 34 taken 22 times.
✓ Branch 34 → 35 taken 22 times.
42 std::sort(sorted.begin(), sorted.end(), [](const Interval &a, const Interval &b) { return a.start < b.start; });
19 759 const auto overlaps = [&sorted](const QDateTime &start, const QDateTime &end) {
20
4/4
✓ Branch 2 → 3 taken 759 times.
✓ Branch 3 → 4 taken 759 times.
✓ Branch 16 → 5 taken 858 times.
✓ Branch 16 → 17 taken 429 times.
1287 for (const Interval &interval : sorted) {
21
3/3
✓ Branch 6 → 7 taken 858 times.
✓ Branch 8 → 9 taken 237 times.
✓ Branch 8 → 10 taken 621 times.
951 if (interval.start >= end) return false;
22
3/3
✓ Branch 10 → 11 taken 621 times.
✓ Branch 12 → 13 taken 93 times.
✓ Branch 12 → 14 taken 528 times.
621 if (interval.end > start) return true;
23 }
24 429 return false;
25 22 };
26
6/6
✓ Branch 103 → 104 taken 86 times.
✓ Branch 103 → 107 taken 4 times.
✓ Branch 105 → 106 taken 68 times.
✓ Branch 105 → 107 taken 18 times.
✓ Branch 108 → 36 taken 68 times.
✓ Branch 108 → 109 taken 22 times.
90 for (int day = 0; day < days && found.size() < maximum; ++day) {
27
1/1
✓ Branch 36 → 37 taken 68 times.
68 const QDate date = options.from.addDays(day);
28
3/3
✓ Branch 37 → 38 taken 68 times.
✓ Branch 39 → 40 taken 4 times.
✓ Branch 39 → 41 taken 64 times.
68 if (!options.workingDays.contains(date.dayOfWeek())) continue;
29
1/1
✓ Branch 41 → 42 taken 64 times.
64 const QDateTime dayEnd(date, options.dayEnd, options.zone);
30
8/9
✓ Branch 89 → 90 taken 1113 times.
✓ Branch 90 → 91 taken 1113 times.
✗ Branch 90 → 97 not taken.
✓ Branch 93 → 94 taken 1069 times.
✓ Branch 93 → 97 taken 44 times.
✓ Branch 95 → 96 taken 1051 times.
✓ Branch 95 → 97 taken 18 times.
✓ Branch 98 → 43 taken 1051 times.
✓ Branch 98 → 99 taken 62 times.
1113 for (QTime time = options.dayStart; time.isValid() && time < options.dayEnd && found.size() < maximum;) {
31
1/1
✓ Branch 43 → 44 taken 1051 times.
1051 const QDateTime start(date, time, options.zone);
32
1/1
✓ Branch 44 → 45 taken 1051 times.
1051 const QDateTime end = start.addSecs(qint64(duration) * 60);
33 // The spring gap: Qt moves a missing wall time; such a slot is skipped.
34
7/9
✓ Branch 45 → 46 taken 1051 times.
✓ Branch 46 → 47 taken 1051 times.
✗ Branch 46 → 54 not taken.
✓ Branch 47 → 48 taken 1051 times.
✓ Branch 49 → 50 taken 1049 times.
✓ Branch 49 → 54 taken 2 times.
✓ Branch 50 → 51 taken 1049 times.
✓ Branch 52 → 53 taken 1049 times.
✗ Branch 52 → 54 not taken.
1051 const bool exists = start.isValid() && start.time() == time && start.date() == date;
35
13/13
✓ Branch 55 → 56 taken 1049 times.
✓ Branch 55 → 67 taken 2 times.
✓ Branch 56 → 57 taken 1049 times.
✓ Branch 58 → 59 taken 1005 times.
✓ Branch 58 → 67 taken 44 times.
✓ Branch 59 → 60 taken 1005 times.
✓ Branch 60 → 61 taken 981 times.
✓ Branch 60 → 64 taken 24 times.
✓ Branch 61 → 62 taken 981 times.
✓ Branch 63 → 64 taken 735 times.
✓ Branch 63 → 67 taken 246 times.
✓ Branch 68 → 69 taken 666 times.
✓ Branch 68 → 74 taken 385 times.
1810 if (exists && end <= dayEnd && (!options.notBefore.isValid() || start >= options.notBefore) &&
36
3/3
✓ Branch 64 → 65 taken 759 times.
✓ Branch 65 → 66 taken 666 times.
✓ Branch 65 → 67 taken 93 times.
759 !overlaps(start, end))
37 666 found.append({start, end});
38
1/1
✓ Branch 74 → 75 taken 1051 times.
1051 const QTime next = time.addSecs(step * 60);
39
2/2
✓ Branch 77 → 78 taken 2 times.
✓ Branch 77 → 79 taken 1049 times.
1051 if (next <= time) break; // past midnight
40 1049 time = next;
41 1053 }
42 64 }
43 22 return found;
44 688 }
45
46 45 QList<Span> daySpans(const QList<Interval> &busy, const QDate &day, const QTime &dayStart, const QTime &dayEnd,
47 const QTimeZone &zone) {
48
1/1
✓ Branch 2 → 3 taken 45 times.
45 const QDateTime windowStart(day, dayStart, zone);
49
1/1
✓ Branch 3 → 4 taken 45 times.
45 const QDateTime windowEnd(day, dayEnd, zone);
50
1/1
✓ Branch 4 → 5 taken 45 times.
45 const double length = double(windowStart.msecsTo(windowEnd));
51 45 QList<Span> spans;
52
8/10
✓ Branch 5 → 6 taken 45 times.
✓ Branch 6 → 7 taken 45 times.
✗ Branch 6 → 10 not taken.
✓ Branch 7 → 8 taken 45 times.
✓ Branch 8 → 9 taken 45 times.
✗ Branch 8 → 10 not taken.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 44 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 15 taken 44 times.
45 if (!windowStart.isValid() || !windowEnd.isValid() || length <= 0) return spans;
53
2/2
✓ Branch 41 → 17 taken 56 times.
✓ Branch 41 → 42 taken 44 times.
100 for (const Interval &interval : busy) {
54
1/1
✓ Branch 18 → 19 taken 56 times.
56 const QDateTime start = std::max(interval.start, windowStart);
55
1/1
✓ Branch 20 → 21 taken 56 times.
56 const QDateTime end = std::min(interval.end, windowEnd);
56
3/3
✓ Branch 22 → 23 taken 56 times.
✓ Branch 24 → 25 taken 31 times.
✓ Branch 24 → 26 taken 25 times.
56 if (end <= start) continue;
57
3/3
✓ Branch 26 → 27 taken 25 times.
✓ Branch 27 → 28 taken 25 times.
✓ Branch 28 → 29 taken 25 times.
25 spans.append({windowStart.msecsTo(start) / length, windowStart.msecsTo(end) / length});
58 87 }
59
3/3
✓ Branch 42 → 43 taken 44 times.
✓ Branch 43 → 44 taken 44 times.
✓ Branch 44 → 45 taken 44 times.
64 std::sort(spans.begin(), spans.end(), [](const Span &a, const Span &b) { return a.from < b.from; });
60 44 QList<Span> merged;
61
4/4
✓ Branch 45 → 46 taken 44 times.
✓ Branch 46 → 47 taken 44 times.
✓ Branch 63 → 48 taken 25 times.
✓ Branch 63 → 64 taken 44 times.
69 for (const Span &span : spans) {
62
9/9
✓ Branch 50 → 51 taken 10 times.
✓ Branch 50 → 54 taken 15 times.
✓ Branch 51 → 52 taken 10 times.
✓ Branch 52 → 53 taken 2 times.
✓ Branch 52 → 54 taken 8 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 60 taken 23 times.
✓ Branch 56 → 57 taken 2 times.
✓ Branch 58 → 59 taken 2 times.
25 if (!merged.isEmpty() && span.from <= merged.last().to) merged.last().to = std::max(merged.last().to, span.to);
63
1/1
✓ Branch 60 → 61 taken 23 times.
23 else merged.append(span);
64 }
65 44 return merged;
66 45 }
67
68 } // namespace FreeSlots
69