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% 82 / 0 / 82
Functions: 100.0% 12 / 0 / 12
Branches: 94.1% 128 / 0 / 136

data/RelationGraphHouseholds.cpp
Line Branch Exec Source
1 // The households of a generation row (declared in RelationGraphRows.h,
2 // split from RelationGraphRows.cpp).
3 #include "RelationGraphRows.h"
4
5 #include <QMap>
6 #include <QSet>
7 #include <algorithm>
8
9 namespace RelationGraphLayout {
10
11 namespace {
12
13 1843 bool byName(const RelationGraph::Graph &graph, int a, int b) {
14 1843 const int c = graph.nodes.at(a).name.localeAwareCompare(graph.nodes.at(b).name);
15
1/2
✓ Branch 5 → 6 taken 1843 times.
✗ Branch 5 → 7 not taken.
1843 return c != 0 ? c < 0 : graph.nodes.at(a).key < graph.nodes.at(b).key;
16 }
17
18 // The birthday with a year ("1988-04-12"), else "" (unknown or "--06-14").
19 4322 QString datedBirthday(const RelationGraph::Node &node) {
20
5/5
✓ Branch 3 → 4 taken 480 times.
✓ Branch 3 → 8 taken 3842 times.
✓ Branch 5 → 6 taken 480 times.
✓ Branch 6 → 7 taken 415 times.
✓ Branch 6 → 8 taken 65 times.
4322 return node.birthday.size() >= 4 && !node.birthday.startsWith(QLatin1String("--")) ? node.birthday : QString();
21 }
22
23 // Siblings as a family tree orders them: the older first, those without a
24 // known year after them by name.
25 2161 bool byAge(const RelationGraph::Graph &graph, int a, int b) {
26
2/2
✓ Branch 3 → 4 taken 2161 times.
✓ Branch 5 → 6 taken 2161 times.
2161 const QString da = datedBirthday(graph.nodes.at(a)), db = datedBirthday(graph.nodes.at(b));
27
2/2
✓ Branch 8 → 9 taken 221 times.
✓ Branch 8 → 11 taken 1940 times.
2161 if (da.isEmpty() != db.isEmpty())
28 221 return !da.isEmpty();
29
2/2
✓ Branch 12 → 13 taken 97 times.
✓ Branch 12 → 15 taken 1843 times.
1940 if (da != db)
30 97 return da < db;
31
1/1
✓ Branch 15 → 16 taken 1843 times.
1843 return byName(graph, a, b);
32 2161 }
33
34 } // namespace
35
36 763 QList<QList<int>> households(const RelationGraph::Graph &graph, const QList<int> &row,
37 const QSet<QPair<int, int>> &siblings, const QHash<int, int> &partnerOf) {
38
1/1
✓ Branch 4 → 5 taken 763 times.
763 const QSet<int> inRow(row.cbegin(), row.cend());
39 763 QHash<int, int> group; // sibling group: the smallest index of the group
40 5687 const auto find = [&group](int i) {
41
2/2
✓ Branch 6 → 3 taken 787 times.
✓ Branch 6 → 7 taken 5687 times.
6474 while (group.value(i, i) != i)
42 787 i = group.value(i, i);
43 5687 return i;
44 763 };
45
2/2
✓ Branch 30 → 7 taken 1475 times.
✓ Branch 30 → 31 taken 763 times.
2238 for (const auto &[a, b] : siblings)
46
7/8
✓ Branch 11 → 12 taken 538 times.
✓ Branch 11 → 18 taken 937 times.
✓ Branch 13 → 14 taken 538 times.
✗ Branch 13 → 18 not taken.
✓ Branch 16 → 17 taken 510 times.
✓ Branch 16 → 18 taken 28 times.
✓ Branch 19 → 20 taken 510 times.
✓ Branch 19 → 28 taken 965 times.
1475 if (inRow.contains(a) && inRow.contains(b) && find(a) != find(b))
47
1/1
✓ Branch 26 → 27 taken 510 times.
510 group.insert(std::max(find(a), find(b)), std::min(find(a), find(b)));
48 763 QMap<int, QList<int>> groups; // group id → members, the oldest first
49
2/2
✓ Branch 39 → 33 taken 1891 times.
✓ Branch 39 → 40 taken 763 times.
2654 for (int node : row)
50
2/2
✓ Branch 35 → 36 taken 1891 times.
✓ Branch 36 → 37 taken 1891 times.
1891 groups[find(node)].append(node);
51
4/4
✓ Branch 40 → 41 taken 763 times.
✓ Branch 41 → 42 taken 763 times.
✓ Branch 49 → 43 taken 1381 times.
✓ Branch 49 → 50 taken 763 times.
2144 for (QList<int> &members : groups)
52
3/3
✓ Branch 44 → 45 taken 1381 times.
✓ Branch 45 → 46 taken 1381 times.
✓ Branch 46 → 47 taken 1381 times.
2382 std::sort(members.begin(), members.end(), [&graph](int a, int b) { return byAge(graph, a, b); });
53 7247 const auto partnerIn = [&](int node) {
54 7247 const int partner = partnerOf.value(node, -1);
55
2/2
✓ Branch 4 → 5 taken 3171 times.
✓ Branch 4 → 6 taken 4076 times.
7247 return inRow.contains(partner) ? partner : -1;
56 763 };
57 // Groups in order of their first (oldest) person — so children of one
58 // couple who are not joined as siblings stand oldest first, too; each
59 // starts a chain unless it is reached through a partner.
60
1/1
✓ Branch 50 → 51 taken 763 times.
763 QList<int> starts = groups.keys();
61
3/3
✓ Branch 51 → 52 taken 763 times.
✓ Branch 52 → 53 taken 763 times.
✓ Branch 53 → 54 taken 763 times.
763 std::sort(starts.begin(), starts.end(), [&](int a, int b) {
62
3/3
✓ Branch 3 → 4 taken 1265 times.
✓ Branch 6 → 7 taken 1265 times.
✓ Branch 8 → 9 taken 1265 times.
2797 const int la = int(std::count_if(groups.value(a).cbegin(), groups.value(a).cend(), [&](int n) { return partnerIn(n) >= 0; }));
63
3/3
✓ Branch 14 → 15 taken 1265 times.
✓ Branch 17 → 18 taken 1265 times.
✓ Branch 19 → 20 taken 1265 times.
3208 const int lb = int(std::count_if(groups.value(b).cbegin(), groups.value(b).cend(), [&](int n) { return partnerIn(n) >= 0; }));
64
2/2
✓ Branch 24 → 25 taken 105 times.
✓ Branch 24 → 26 taken 1160 times.
1265 if ((la <= 1) != (lb <= 1))
65 105 return la <= 1; // a chain's end first
66
5/5
✓ Branch 27 → 28 taken 1160 times.
✓ Branch 28 → 29 taken 1160 times.
✓ Branch 30 → 31 taken 1160 times.
✓ Branch 31 → 32 taken 1160 times.
✓ Branch 32 → 33 taken 1160 times.
1160 return byAge(graph, groups.value(a).first(), groups.value(b).first());
67 });
68 763 QSet<int> done; // people placed
69 // How many people of a sibling group are still to be placed.
70 1061 const auto open = [&](int groupId) {
71
3/3
✓ Branch 3 → 4 taken 1061 times.
✓ Branch 6 → 7 taken 1061 times.
✓ Branch 8 → 9 taken 1061 times.
2122 return int(std::count_if(groups.value(groupId).cbegin(), groups.value(groupId).cend(),
72 3556 [&](int n) { return !done.contains(n); }));
73 763 };
74 763 QList<QList<int>> order;
75 763 QSet<int> visited; // sibling groups
76
2/2
✓ Branch 163 → 59 taken 1381 times.
✓ Branch 163 → 164 taken 763 times.
2144 for (int start : std::as_const(starts)) {
77
7/7
✓ Branch 61 → 62 taken 1051 times.
✓ Branch 61 → 64 taken 330 times.
✓ Branch 62 → 63 taken 1051 times.
✓ Branch 63 → 64 taken 5 times.
✓ Branch 63 → 65 taken 1046 times.
✓ Branch 66 → 67 taken 335 times.
✓ Branch 66 → 68 taken 1046 times.
1381 if (visited.contains(start) || open(start) == 0) // all taken in by their partners
78 335 continue;
79
1/1
✓ Branch 69 → 70 taken 1046 times.
1046 order.append(QList<int>{});
80 1046 int current = start, entry = -1;
81
5/6
✓ Branch 154 → 155 taken 1376 times.
✓ Branch 154 → 158 taken 1046 times.
✓ Branch 156 → 157 taken 1376 times.
✗ Branch 156 → 158 not taken.
✓ Branch 159 → 72 taken 1376 times.
✓ Branch 159 → 160 taken 1046 times.
2422 while (current >= 0 && !visited.contains(current)) {
82
1/1
✓ Branch 72 → 73 taken 1376 times.
1376 visited.insert(current);
83 1376 QList<int> members;
84
5/5
✓ Branch 74 → 75 taken 1376 times.
✓ Branch 76 → 77 taken 1376 times.
✓ Branch 77 → 78 taken 1376 times.
✓ Branch 85 → 79 taken 1886 times.
✓ Branch 85 → 86 taken 1376 times.
3262 for (int node : groups.value(current))
85
1/2
✓ Branch 81 → 82 taken 1886 times.
✗ Branch 81 → 83 not taken.
1886 if (!done.contains(node))
86
1/1
✓ Branch 82 → 83 taken 1886 times.
3262 members.append(node);
87 // The chain goes on through the partner whose own siblings are most.
88 1376 int exit = -1, next = -1;
89
2/2
✓ Branch 116 → 90 taken 1886 times.
✓ Branch 116 → 117 taken 1376 times.
3262 for (int node : std::as_const(members)) {
90
1/1
✓ Branch 91 → 92 taken 1886 times.
1886 const int partner = partnerIn(node);
91
8/10
✓ Branch 92 → 93 taken 1556 times.
✓ Branch 92 → 99 taken 330 times.
✓ Branch 93 → 94 taken 335 times.
✓ Branch 93 → 99 taken 1221 times.
✓ Branch 95 → 96 taken 335 times.
✗ Branch 95 → 99 not taken.
✗ Branch 98 → 99 not taken.
✓ Branch 98 → 100 taken 335 times.
✓ Branch 101 → 102 taken 1551 times.
✓ Branch 101 → 103 taken 335 times.
1886 if (node == entry || partner < 0 || done.contains(partner) || visited.contains(find(partner)))
92 1551 continue;
93
8/8
✓ Branch 103 → 104 taken 5 times.
✓ Branch 103 → 109 taken 330 times.
✓ Branch 105 → 106 taken 5 times.
✓ Branch 107 → 108 taken 5 times.
✓ Branch 108 → 109 taken 1 time.
✓ Branch 108 → 110 taken 4 times.
✓ Branch 111 → 112 taken 331 times.
✓ Branch 111 → 113 taken 4 times.
335 if (next < 0 || open(find(partner)) > open(find(next))) {
94 331 exit = node;
95 331 next = partner;
96 }
97 }
98
2/2
✓ Branch 117 → 118 taken 330 times.
✓ Branch 117 → 120 taken 1046 times.
1376 if (entry >= 0)
99
1/1
✓ Branch 119 → 120 taken 330 times.
330 members.move(int(members.indexOf(entry)), 0);
100
2/2
✓ Branch 120 → 121 taken 330 times.
✓ Branch 120 → 124 taken 1046 times.
1376 if (exit >= 0)
101
1/1
✓ Branch 123 → 124 taken 330 times.
330 members.move(int(members.indexOf(exit)), int(members.size()) - 1);
102 // Every other partner stands right beside their partner (and leaves
103 // their own siblings): a couple is never split.
104
2/2
✓ Branch 148 → 127 taken 1886 times.
✓ Branch 148 → 149 taken 1376 times.
3262 for (int node : std::as_const(members)) {
105
2/2
✓ Branch 128 → 129 taken 1886 times.
✓ Branch 129 → 130 taken 1886 times.
1886 order.last().append(node);
106
1/1
✓ Branch 130 → 131 taken 1886 times.
1886 done.insert(node);
107
1/1
✓ Branch 131 → 132 taken 1886 times.
1886 const int partner = partnerIn(node);
108
10/12
✓ Branch 132 → 133 taken 1556 times.
✓ Branch 132 → 140 taken 330 times.
✓ Branch 133 → 134 taken 1226 times.
✓ Branch 133 → 140 taken 330 times.
✓ Branch 134 → 135 taken 5 times.
✓ Branch 134 → 140 taken 1221 times.
✓ Branch 136 → 137 taken 5 times.
✗ Branch 136 → 140 not taken.
✓ Branch 138 → 139 taken 5 times.
✗ Branch 138 → 140 not taken.
✓ Branch 141 → 142 taken 5 times.
✓ Branch 141 → 146 taken 1881 times.
1886 if (node != entry && node != exit && partner >= 0 && !done.contains(partner) && find(partner) != current) {
109
2/2
✓ Branch 142 → 143 taken 5 times.
✓ Branch 143 → 144 taken 5 times.
5 order.last().append(partner);
110
1/1
✓ Branch 144 → 145 taken 5 times.
5 done.insert(partner);
111 }
112 }
113 1376 entry = next;
114
2/2
✓ Branch 149 → 150 taken 330 times.
✓ Branch 149 → 151 taken 1046 times.
1376 current = next >= 0 ? find(next) : -1;
115 1376 }
116 }
117 763 return order;
118 763 }
119
120 } // namespace RelationGraphLayout
121