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: 98.6% 70 / 0 / 71
Functions: 100.0% 6 / 0 / 6
Branches: 90.2% 74 / 0 / 82

data/RelationGraphCompact.cpp
Line Branch Exec Source
1 // RelationGraphForce::compact — pulls separated blocks together (declared in
2 // RelationGraphForce.h, split from RelationGraphForce.cpp).
3 #include "RelationGraphForce.h"
4
5 #include <algorithm>
6 #include <cmath>
7 #include <numeric>
8 #include <vector>
9
10 namespace RelationGraphForce {
11
12 7 void compact(QList<QPointF> *positions, const QList<QSizeF> &sizes, const QList<bool> &pinned, double gap,
13 const QList<QPair<int, int>> &links, int limit) {
14 7 QList<QPointF> &pos = *positions;
15 7 const int n = int(pos.size());
16
3/4
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 3 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 4 times.
7 if (n < 2 || n > limit)
17 3 return;
18 4 QPointF middle;
19
2/2
✓ Branch 13 → 9 taken 34 times.
✓ Branch 13 → 14 taken 4 times.
38 for (const QPointF &p : std::as_const(pos))
20 34 middle += p;
21 4 middle /= n;
22
1/1
✓ Branch 15 → 16 taken 4 times.
4 QList<QList<int>> neighbours(n);
23
2/2
✓ Branch 32 → 18 taken 83 times.
✓ Branch 32 → 33 taken 4 times.
87 for (const auto &[a, b] : links)
24
5/10
✓ Branch 21 → 22 taken 83 times.
✗ Branch 21 → 30 not taken.
✓ Branch 22 → 23 taken 83 times.
✗ Branch 22 → 30 not taken.
✓ Branch 23 → 24 taken 83 times.
✗ Branch 23 → 30 not taken.
✓ Branch 24 → 25 taken 83 times.
✗ Branch 24 → 30 not taken.
✓ Branch 25 → 26 taken 83 times.
✗ Branch 25 → 30 not taken.
83 if (a >= 0 && b >= 0 && a < n && b < n && a != b) {
25
2/2
✓ Branch 26 → 27 taken 83 times.
✓ Branch 27 → 28 taken 83 times.
83 neighbours[a].append(b);
26
2/2
✓ Branch 28 → 29 taken 83 times.
✓ Branch 29 → 30 taken 83 times.
83 neighbours[b].append(a);
27 }
28 419 const auto clear = [&](int i, QPointF at) {
29
2/2
✓ Branch 27 → 3 taken 2644 times.
✓ Branch 27 → 28 taken 14 times.
2658 for (int j = 0; j < n; ++j)
30
6/6
✓ Branch 3 → 4 taken 2552 times.
✓ Branch 3 → 23 taken 92 times.
✓ Branch 12 → 13 taken 1105 times.
✓ Branch 12 → 23 taken 1447 times.
✓ Branch 24 → 25 taken 405 times.
✓ Branch 24 → 26 taken 2239 times.
3749 if (j != i && std::abs(at.x() - pos.at(j).x()) < (sizes.at(i).width() + sizes.at(j).width()) / 2 + gap &&
31
2/2
✓ Branch 21 → 22 taken 405 times.
✓ Branch 21 → 23 taken 700 times.
1105 std::abs(at.y() - pos.at(j).y()) < (sizes.at(i).height() + sizes.at(j).height()) / 2 + gap)
32 405 return false;
33 14 return true;
34 4 };
35 // Moves `i` towards `target` to the closest free point, in 5 % steps.
36 16 const auto pull = [&](int i, QPointF target) {
37 16 const QPointF from = pos.at(i);
38
2/2
✓ Branch 13 → 4 taken 151 times.
✓ Branch 13 → 14 taken 3 times.
154 for (int step = 20; step > 0; --step) {
39 151 const QPointF at = target + (from - target) * (20 - step) / 20.0;
40
2/2
✓ Branch 9 → 10 taken 13 times.
✓ Branch 9 → 12 taken 138 times.
151 if (clear(i, at)) {
41
1/1
✓ Branch 10 → 11 taken 13 times.
13 pos[i] = at;
42 13 return;
43 }
44 }
45 4 };
46 // Then, beside its neighbours: the free place nearest to `target` on rings
47 // around it, when that is closer than the line got (a wide block on the
48 // line stops the pull at its far rim). Up to 150 rectangles (cost).
49 4 const auto settle = [&](int i, QPointF target) {
50
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4 times.
4 if (n > 150)
51 ✗ return;
52 4 const double distance = std::hypot(pos.at(i).x() - target.x(), pos.at(i).y() - target.y());
53 4 const double step = std::min(sizes.at(i).width(), sizes.at(i).height()) / 2 + gap;
54
3/4
✓ Branch 37 → 38 taken 18 times.
✗ Branch 37 → 39 not taken.
✓ Branch 38 → 16 taken 15 times.
✓ Branch 38 → 39 taken 3 times.
18 for (int ring = 1; ring <= 24 && ring * step < distance; ++ring) {
55 15 QPointF best;
56 15 double bestDistance = distance;
57
2/2
✓ Branch 32 → 17 taken 296 times.
✓ Branch 32 → 33 taken 15 times.
311 for (int k = 0; k < 8 * ring; ++k) {
58 296 const double angle = 2 * M_PI * k / (8 * ring);
59 296 const QPointF at = target + QPointF(std::cos(angle), std::sin(angle)) * (ring * step);
60 296 const double d = std::hypot(at.x() - target.x(), at.y() - target.y());
61
6/6
✓ Branch 24 → 25 taken 268 times.
✓ Branch 24 → 28 taken 28 times.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 28 taken 267 times.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 295 times.
296 if (d < bestDistance && clear(i, at)) {
62 1 best = at;
63 1 bestDistance = d;
64 }
65 }
66
2/2
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 36 taken 14 times.
15 if (bestDistance < distance) {
67
1/1
✓ Branch 34 → 35 taken 1 time.
1 pos[i] = best;
68 1 return;
69 }
70 }
71 4 };
72
1/1
✓ Branch 35 → 36 taken 4 times.
4 std::vector<int> order(static_cast<size_t>(n));
73 4 std::iota(order.begin(), order.end(), 0);
74
1/1
✓ Branch 42 → 43 taken 4 times.
4 std::sort(order.begin(), order.end(), [&](int a, int b) {
75 144 const double da = std::hypot(pos.at(a).x() - middle.x(), pos.at(a).y() - middle.y());
76 144 const double db = std::hypot(pos.at(b).x() - middle.x(), pos.at(b).y() - middle.y());
77
2/2
✓ Branch 14 → 15 taken 140 times.
✓ Branch 14 → 16 taken 4 times.
144 return da != db ? da < db : a < b;
78 });
79 // Screens are wider than tall: first onto the middle line (a wide band), then towards the middle.
80
2/2
✓ Branch 56 → 45 taken 34 times.
✓ Branch 56 → 57 taken 4 times.
38 for (const int i : order)
81
3/3
✓ Branch 46 → 47 taken 34 times.
✓ Branch 47 → 48 taken 6 times.
✓ Branch 47 → 54 taken 28 times.
34 if (!pinned.value(i)) {
82
1/1
✓ Branch 52 → 53 taken 6 times.
6 pull(i, QPointF(pos.at(i).x(), middle.y()));
83
1/1
✓ Branch 53 → 54 taken 6 times.
6 pull(i, middle);
84 }
85 // Then towards the linked ones; the larger blocks first stay, small ones come to them.
86
1/1
✓ Branch 59 → 60 taken 4 times.
4 std::stable_sort(order.begin(), order.end(), [&](int a, int b) {
87 112 return sizes.at(a).width() * sizes.at(a).height() > sizes.at(b).width() * sizes.at(b).height();
88 });
89
2/2
✓ Branch 92 → 61 taken 8 times.
✓ Branch 92 → 93 taken 4 times.
12 for (int round = 0; round < 2; ++round)
90
2/2
✓ Branch 90 → 63 taken 68 times.
✓ Branch 90 → 91 taken 8 times.
76 for (const int i : order) {
91
7/7
✓ Branch 64 → 65 taken 68 times.
✓ Branch 65 → 66 taken 12 times.
✓ Branch 65 → 69 taken 56 times.
✓ Branch 68 → 69 taken 8 times.
✓ Branch 68 → 70 taken 4 times.
✓ Branch 71 → 72 taken 64 times.
✓ Branch 71 → 73 taken 4 times.
68 if (pinned.value(i) || neighbours.at(i).isEmpty())
92 64 continue;
93 4 QPointF target;
94
2/2
✓ Branch 81 → 76 taken 26 times.
✓ Branch 81 → 82 taken 4 times.
30 for (int j : neighbours.at(i))
95 26 target += pos.at(j);
96 4 target /= neighbours.at(i).size();
97
1/1
✓ Branch 85 → 86 taken 4 times.
4 pull(i, target);
98
1/1
✓ Branch 86 → 87 taken 4 times.
4 settle(i, target);
99 }
100 4 }
101
102 } // namespace RelationGraphForce
103