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: 87.3% 62 / 0 / 71
Functions: 100.0% 2 / 0 / 2
Branches: 60.2% 151 / 0 / 251

app/NamedCommandCatalogReference.cpp
Line Branch Exec Source
1 // The checks and the generated reference of the command catalog (split from
2 // NamedCommandCatalog.cpp, which holds the commands and the parser): the
3 // lint of D-14/D-15/D-15a/D-18 and docs/COMMANDS.md.
4
5 #include "NamedCommandCatalog.h"
6 #include <QRegularExpression>
7 #include <QSet>
8
9 1 QStringList NamedCommandCatalog::lint() {
10
3/7
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 15 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 252 → 253 not taken.
✗ Branch 252 → 254 not taken.
2 static const QRegularExpression word(QStringLiteral("^[a-z]+$"));
11 1 QStringList problems;
12 1 QSet<QString> seen;
13
3/3
✓ Branch 16 → 17 taken 1 time.
✓ Branch 241 → 19 taken 52 times.
✓ Branch 241 → 242 taken 1 time.
53 for (const auto &command : specs()) {
14 52 const QString name = command.name;
15
3/6
✓ Branch 22 → 23 taken 52 times.
✓ Branch 23 → 24 taken 52 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 30 taken 52 times.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
52 if (!word.match(name).hasMatch()) problems << name + ": a name is one lowercase English word (D-15)";
16
1/4
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 36 taken 52 times.
✗ Branch 32 → 33 not taken.
✗ Branch 33 → 34 not taken.
52 if (seen.contains(name)) problems << name + ": duplicate name";
17
1/1
✓ Branch 36 → 37 taken 52 times.
52 seen.insert(name);
18
1/4
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 43 taken 52 times.
✗ Branch 39 → 40 not taken.
✗ Branch 40 → 41 not taken.
52 if (!command.aliases.isEmpty()) problems << name + ": aliases are not allowed (D-14)";
19
2/6
✓ Branch 43 → 44 taken 52 times.
✗ Branch 43 → 45 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 49 taken 52 times.
✗ Branch 45 → 46 not taken.
✗ Branch 46 → 47 not taken.
52 if (!*command.description || !*command.category) problems << name + ": description and category are required";
20
1/4
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 54 taken 52 times.
✗ Branch 50 → 51 not taken.
✗ Branch 51 → 52 not taken.
52 if (!*command.keywords) problems << name + ": keywords are required (D-14)";
21
8/12
✓ Branch 54 → 55 taken 27 times.
✓ Branch 54 → 60 taken 25 times.
✓ Branch 56 → 57 taken 27 times.
✓ Branch 57 → 58 taken 27 times.
✗ Branch 58 → 59 not taken.
✓ Branch 58 → 60 taken 27 times.
✓ Branch 61 → 62 taken 27 times.
✓ Branch 61 → 63 taken 25 times.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 73 taken 52 times.
✗ Branch 275 → 276 not taken.
✗ Branch 275 → 277 not taken.
52 if (command.registryId && !CommandRegistry::find(QString::fromLatin1(command.registryId)))
22 ✗ problems << name + ": unknown registry id " + QString::fromLatin1(command.registryId);
23
3/6
✓ Branch 73 → 74 taken 38 times.
✓ Branch 73 → 79 taken 14 times.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 79 taken 38 times.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
52 if (command.argument != CommandArgument::None && !*command.syntax) problems << name + ": syntax is required";
24
4/6
✓ Branch 79 → 80 taken 17 times.
✓ Branch 79 → 83 taken 35 times.
✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 17 times.
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 89 taken 52 times.
52 if (command.argument == CommandArgument::Values && command.values.isEmpty())
25 ✗ problems << name + ": a value argument needs values";
26 // D-15a: several values or labels; the syntax shows it with "…".
27
5/6
✓ Branch 89 → 90 taken 5 times.
✓ Branch 89 → 96 taken 47 times.
✓ Branch 90 → 91 taken 2 times.
✓ Branch 90 → 96 taken 3 times.
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 96 taken 2 times.
52 if (command.several && command.argument != CommandArgument::Values && command.argument != CommandArgument::Label)
28 ✗ problems << name + ": only values and labels can be several";
29
3/4
✓ Branch 97 → 98 taken 52 times.
✓ Branch 101 → 102 taken 52 times.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 110 taken 52 times.
104 if (command.several != QString::fromUtf8(command.syntax).contains(QStringLiteral("…")))
30 ✗ problems << name + ": the syntax of a command with several values ends in \"…\" (D-15a)";
31 52 QSet<QString> values;
32
2/2
✓ Branch 236 → 113 taken 56 times.
✓ Branch 236 → 237 taken 52 times.
108 for (const auto &value : command.values) {
33
1/1
✓ Branch 115 → 116 taken 56 times.
56 const QString valueWord = QString::fromLatin1(value.word);
34
3/8
✓ Branch 117 → 118 taken 56 times.
✓ Branch 118 → 119 taken 56 times.
✗ Branch 120 → 121 not taken.
✓ Branch 120 → 129 taken 56 times.
✗ Branch 121 → 122 not taken.
✗ Branch 122 → 123 not taken.
✗ Branch 123 → 124 not taken.
✗ Branch 124 → 125 not taken.
56 if (!word.match(valueWord).hasMatch()) problems << name + " " + valueWord + ": a value is one lowercase word";
35
1/6
✗ Branch 130 → 131 not taken.
✓ Branch 130 → 139 taken 56 times.
✗ Branch 131 → 132 not taken.
✗ Branch 132 → 133 not taken.
✗ Branch 133 → 134 not taken.
✗ Branch 134 → 135 not taken.
56 if (values.contains(valueWord)) problems << name + " " + valueWord + ": duplicate value";
36
1/1
✓ Branch 139 → 140 taken 56 times.
56 values.insert(valueWord);
37
2/8
✓ Branch 140 → 141 taken 56 times.
✗ Branch 140 → 142 not taken.
✗ Branch 141 → 142 not taken.
✓ Branch 141 → 150 taken 56 times.
✗ Branch 142 → 143 not taken.
✗ Branch 143 → 144 not taken.
✗ Branch 144 → 145 not taken.
✗ Branch 145 → 146 not taken.
56 if (!*value.description || !*value.keywords) problems << name + " " + valueWord + ": description and keywords";
38
8/12
✓ Branch 150 → 151 taken 14 times.
✓ Branch 150 → 156 taken 42 times.
✓ Branch 152 → 153 taken 14 times.
✓ Branch 153 → 154 taken 14 times.
✗ Branch 154 → 155 not taken.
✓ Branch 154 → 156 taken 14 times.
✓ Branch 157 → 158 taken 14 times.
✓ Branch 157 → 159 taken 42 times.
✗ Branch 159 → 160 not taken.
✓ Branch 159 → 168 taken 56 times.
✗ Branch 345 → 346 not taken.
✗ Branch 345 → 347 not taken.
56 if (value.registryId && !CommandRegistry::find(QString::fromLatin1(value.registryId)))
39 ✗ problems << name + " " + valueWord + ": unknown registry id";
40
3/4
✓ Branch 168 → 169 taken 12 times.
✓ Branch 168 → 178 taken 44 times.
✗ Branch 169 → 170 not taken.
✓ Branch 169 → 178 taken 12 times.
56 if (command.several && value.then != CommandArgument::None)
41 ✗ problems << name + " " + valueWord + ": a value of several takes nothing after it (D-15a)";
42
4/6
✓ Branch 178 → 179 taken 44 times.
✓ Branch 178 → 189 taken 12 times.
✓ Branch 179 → 180 taken 44 times.
✗ Branch 179 → 181 not taken.
✗ Branch 180 → 181 not taken.
✓ Branch 180 → 189 taken 44 times.
56 if (!command.several && (value.group || value.alone))
43 ✗ problems << name + " " + valueWord + ": groups and 'alone' only on commands with several values";
44 // D-15: "on" means a state and exists only on toggles; "off" on
45 // toggles and on the state-like "filter"/"vacation".
46
4/8
✓ Branch 191 → 192 taken 7 times.
✓ Branch 191 → 194 taken 49 times.
✗ Branch 192 → 193 not taken.
✓ Branch 192 → 194 taken 7 times.
✗ Branch 195 → 196 not taken.
✓ Branch 195 → 200 taken 56 times.
✗ Branch 196 → 197 not taken.
✗ Branch 197 → 198 not taken.
56 if (valueWord == QLatin1String("on") && !command.stateKey) problems << name + ": 'on' only on toggles";
47
6/8
✓ Branch 202 → 203 taken 9 times.
✓ Branch 202 → 208 taken 47 times.
✓ Branch 203 → 204 taken 1 time.
✓ Branch 203 → 208 taken 8 times.
✗ Branch 206 → 207 not taken.
✓ Branch 206 → 208 taken 1 time.
✗ Branch 209 → 210 not taken.
✓ Branch 209 → 214 taken 56 times.
56 if (valueWord == QLatin1String("off") && !command.stateKey && name != QLatin1String("filter"))
48 ✗ problems << name + ": 'off' only on toggles and filter";
49
6/6
✓ Branch 216 → 217 taken 3 times.
✓ Branch 216 → 227 taken 53 times.
✓ Branch 219 → 220 taken 2 times.
✓ Branch 219 → 227 taken 1 time.
✓ Branch 222 → 223 taken 1 time.
✓ Branch 222 → 227 taken 1 time.
57 if (valueWord == QLatin1String("all") && name != QLatin1String("reply") && name != QLatin1String("unlabel") &&
50
2/4
✗ Branch 225 → 226 not taken.
✓ Branch 225 → 227 taken 1 time.
✗ Branch 228 → 229 not taken.
✓ Branch 228 → 233 taken 56 times.
57 name != QLatin1String("tasks"))
51 ✗ problems << name + ": 'all' only where it means every recipient/label/task";
52 56 }
53 52 }
54 1 return problems;
55 1 }
56
57 1 QString NamedCommandCatalog::referenceSnapshot() {
58 1 QString result = QStringLiteral(
59 "# Command bar commands\n\n"
60 "Generated from `NamedCommandCatalog::referenceSnapshot()` (`src/app/NamedCommandCatalogReference.cpp`);\n"
61 "`test_named_command_catalog` fails when this file is stale. Notation (D-15): `<required>`,\n"
62 "`[optional]`, `a∣b` fixed values, `…` several of them in one line (D-15a: `mark read important`).\n"
63 "Keywords find a command in the command bar; they are never executed. Keys come from\n"
64 "`CommandRegistry`.\n");
65 1 QString category;
66
3/3
✓ Branch 6 → 7 taken 1 time.
✓ Branch 151 → 9 taken 52 times.
✓ Branch 151 → 152 taken 1 time.
53 for (const auto &command : specs()) {
67
2/2
✓ Branch 12 → 13 taken 13 times.
✓ Branch 12 → 27 taken 39 times.
52 if (category != QLatin1String(command.category)) {
68
1/1
✓ Branch 14 → 15 taken 13 times.
13 category = QString::fromLatin1(command.category);
69
2/2
✓ Branch 21 → 22 taken 13 times.
✓ Branch 22 → 23 taken 13 times.
26 result += QStringLiteral("\n## %1\n\n| Command | Description | Key | Keywords |\n|---|---|---|---|\n").arg(category);
70 }
71
6/8
✓ Branch 27 → 28 taken 27 times.
✓ Branch 27 → 32 taken 25 times.
✓ Branch 29 → 30 taken 27 times.
✓ Branch 30 → 31 taken 27 times.
✓ Branch 33 → 34 taken 27 times.
✓ Branch 33 → 35 taken 25 times.
✗ Branch 167 → 168 not taken.
✗ Branch 167 → 169 not taken.
52 const auto *spec = command.registryId ? CommandRegistry::find(QString::fromLatin1(command.registryId)) : nullptr;
72
3/3
✓ Branch 35 → 36 taken 27 times.
✓ Branch 35 → 37 taken 25 times.
✓ Branch 36 → 38 taken 27 times.
52 const QString key = spec ? CommandRegistry::keyText(*spec) : QString{};
73
7/9
✓ Branch 41 → 42 taken 38 times.
✓ Branch 41 → 45 taken 14 times.
✓ Branch 43 → 44 taken 38 times.
✓ Branch 44 → 46 taken 38 times.
✓ Branch 46 → 47 taken 52 times.
✓ Branch 48 → 49 taken 38 times.
✓ Branch 48 → 50 taken 14 times.
✗ Branch 174 → 175 not taken.
✗ Branch 174 → 176 not taken.
52 QString line = QStringLiteral("`%1%2`").arg(command.name, *command.syntax ? " " + QString::fromUtf8(command.syntax) : QString{});
74
1/1
✓ Branch 53 → 54 taken 52 times.
52 QString description = QString::fromUtf8(command.description);
75
3/3
✓ Branch 54 → 55 taken 3 times.
✓ Branch 54 → 62 taken 49 times.
✓ Branch 58 → 59 taken 3 times.
55 if (command.destructive) description += QStringLiteral(" (destructive)");
76
5/5
✓ Branch 62 → 63 taken 38 times.
✓ Branch 62 → 76 taken 14 times.
✓ Branch 68 → 69 taken 38 times.
✓ Branch 69 → 70 taken 38 times.
✓ Branch 70 → 71 taken 38 times.
128 if (*command.example) description += QStringLiteral(" — e.g. `%1`").arg(QString::fromUtf8(command.example));
77
7/9
✓ Branch 82 → 83 taken 25 times.
✓ Branch 82 → 84 taken 27 times.
✓ Branch 84 → 85 taken 27 times.
✓ Branch 85 → 86 taken 27 times.
✓ Branch 86 → 87 taken 52 times.
✓ Branch 90 → 91 taken 27 times.
✓ Branch 90 → 92 taken 25 times.
✗ Branch 211 → 212 not taken.
✗ Branch 211 → 213 not taken.
208 result += QStringLiteral("| %1 | %2 | %3 | %4 |\n").arg(line, description, key.isEmpty() ? QString{} : "`" + key + "`",
78
2/2
✓ Branch 80 → 81 taken 52 times.
✓ Branch 87 → 88 taken 52 times.
156 QString::fromUtf8(command.keywords));
79
2/2
✓ Branch 145 → 97 taken 56 times.
✓ Branch 145 → 146 taken 52 times.
108 for (const auto &value : command.values) {
80
6/8
✓ Branch 98 → 99 taken 14 times.
✓ Branch 98 → 103 taken 42 times.
✓ Branch 100 → 101 taken 14 times.
✓ Branch 101 → 102 taken 14 times.
✓ Branch 104 → 105 taken 14 times.
✓ Branch 104 → 106 taken 42 times.
✗ Branch 227 → 228 not taken.
✗ Branch 227 → 229 not taken.
56 const auto *valueSpec = value.registryId ? CommandRegistry::find(QString::fromLatin1(value.registryId)) : nullptr;
81
3/3
✓ Branch 106 → 107 taken 14 times.
✓ Branch 106 → 108 taken 42 times.
✓ Branch 107 → 109 taken 14 times.
56 const QString valueKey = valueSpec ? CommandRegistry::keyText(*valueSpec) : QString{};
82 112 result += QStringLiteral("| `%1 %2%3` | %4 | %5 | %6 |\n")
83
2/2
✓ Branch 127 → 128 taken 56 times.
✓ Branch 128 → 129 taken 56 times.
112 .arg(command.name, QString::fromLatin1(value.word),
84
6/8
✓ Branch 121 → 122 taken 6 times.
✓ Branch 121 → 125 taken 50 times.
✓ Branch 123 → 124 taken 6 times.
✓ Branch 124 → 126 taken 6 times.
✓ Branch 133 → 134 taken 6 times.
✓ Branch 133 → 135 taken 50 times.
✗ Branch 240 → 241 not taken.
✗ Branch 240 → 242 not taken.
112 *value.thenSyntax ? " " + QString::fromUtf8(value.thenSyntax) : QString{},
85
7/9
✓ Branch 115 → 116 taken 42 times.
✓ Branch 115 → 117 taken 14 times.
✓ Branch 117 → 118 taken 14 times.
✓ Branch 118 → 119 taken 14 times.
✓ Branch 120 → 121 taken 56 times.
✓ Branch 137 → 138 taken 14 times.
✓ Branch 137 → 139 taken 42 times.
✗ Branch 252 → 253 not taken.
✗ Branch 252 → 254 not taken.
112 QString::fromUtf8(value.description), valueKey.isEmpty() ? QString{} : "`" + valueKey + "`",
86
2/2
✓ Branch 113 → 114 taken 56 times.
✓ Branch 129 → 130 taken 56 times.
168 QString::fromUtf8(value.keywords));
87 56 }
88 52 }
89 1 return result;
90 1 }
91