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: 97.6% 82 / 0 / 84
Functions: 100.0% 6 / 0 / 6
Branches: 86.1% 142 / 0 / 165

util/LogConfigurator.cpp
Line Branch Exec Source
1 #include "util/LogConfigurator.h"
2
3 #include <QCommandLineOption>
4 #include <QCommandLineParser>
5 #include <QLoggingCategory>
6 #include <QString>
7 #include <QStringView>
8
9 namespace {
10 // Environment variable names — kept private, accessed only via apply().
11 constexpr const char *kEnvLogLevel = "MAILJD_LOG_LEVEL";
12 constexpr const char *kEnvLogRules = "MAILJD_LOG_RULES";
13
14 // CLI option names — exposed via QCommandLineParser only.
15 constexpr const char *kOptLogLevel = "log-level";
16 constexpr const char *kOptLogRules = "log-rules";
17 constexpr const char *kOptVerbose = "verbose";
18 // NOTE: --verbose is intentionally long-only. main.cpp calls
19 // QCommandLineParser::addVersionOption(), which claims the short name
20 // "-v" (for --version). Registering verbose as ["v","verbose"] made Qt
21 // reject the whole option with "already having an option named 'v'",
22 // which silently broke --verbose entirely. "-v" stays reserved for
23 // --version (the standard Qt/CLI convention).
24 } // namespace
25
26 13 void LogConfigurator::registerOptions(QCommandLineParser &parser) {
27 QCommandLineOption levelOption(
28
1/1
✓ Branch 14 → 15 taken 13 times.
26 QString::fromLatin1(kOptLogLevel),
29 26 QStringLiteral("Log verbosity: off|error|warning|info|debug "
30 "(default: error). Env: %1.")
31
2/2
✓ Branch 11 → 12 taken 13 times.
✓ Branch 12 → 13 taken 13 times.
26 .arg(QString::fromLatin1(kEnvLogLevel)),
32
1/1
✓ Branch 15 → 16 taken 13 times.
52 QStringLiteral("level"));
33 QCommandLineOption rulesOption(
34
1/1
✓ Branch 36 → 37 taken 13 times.
26 QString::fromLatin1(kOptLogRules),
35 26 QStringLiteral("Raw Qt filter rules (overrides --log-level). "
36 "Env: %1.")
37
2/2
✓ Branch 33 → 34 taken 13 times.
✓ Branch 34 → 35 taken 13 times.
26 .arg(QString::fromLatin1(kEnvLogRules)),
38
1/1
✓ Branch 37 → 38 taken 13 times.
52 QStringLiteral("rules"));
39 QCommandLineOption verboseOption(
40
1/1
✓ Branch 52 → 53 taken 13 times.
26 QString::fromLatin1(kOptVerbose),
41
1/1
✓ Branch 53 → 54 taken 13 times.
52 QStringLiteral("Shortcut for --log-level=info"));
42
1/1
✓ Branch 59 → 60 taken 13 times.
13 parser.addOption(levelOption);
43
1/1
✓ Branch 60 → 61 taken 13 times.
13 parser.addOption(rulesOption);
44
1/1
✓ Branch 61 → 62 taken 13 times.
13 parser.addOption(verboseOption);
45 13 }
46
47 11 QString LogConfigurator::apply(const QCommandLineParser &parser) {
48 // S106-220: the documented order, first one set wins — --log-rules,
49 // --log-level / --verbose, MAILJD_LOG_RULES, MAILJD_LOG_LEVEL, Error. The
50 // environment used to beat an explicit command-line level.
51
2/2
✓ Branch 3 → 4 taken 11 times.
✓ Branch 4 → 5 taken 11 times.
11 const bool cliRules = parser.isSet(QString::fromLatin1(kOptLogRules));
52
11/16
✓ Branch 7 → 8 taken 11 times.
✓ Branch 8 → 9 taken 11 times.
✓ Branch 9 → 10 taken 7 times.
✓ Branch 9 → 14 taken 4 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 12 → 13 taken 7 times.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 5 times.
✓ Branch 16 → 17 taken 7 times.
✓ Branch 16 → 18 taken 4 times.
✓ Branch 18 → 19 taken 11 times.
✗ Branch 18 → 20 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 87 not taken.
11 const bool cliLevel = parser.isSet(QString::fromLatin1(kOptLogLevel)) || parser.isSet(QString::fromLatin1(kOptVerbose));
53 11 QString customRules;
54 11 Level level = Error;
55
2/2
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 28 taken 10 times.
11 if (cliRules) {
56
2/2
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
1 customRules = parser.value(QString::fromLatin1(kOptLogRules));
57
2/2
✓ Branch 28 → 29 taken 5 times.
✓ Branch 28 → 45 taken 5 times.
10 } else if (cliLevel) {
58
2/2
✓ Branch 30 → 31 taken 5 times.
✓ Branch 31 → 32 taken 5 times.
10 level = parser.isSet(QString::fromLatin1(kOptLogLevel))
59
9/13
✓ Branch 32 → 33 taken 3 times.
✓ Branch 32 → 38 taken 2 times.
✓ Branch 34 → 35 taken 3 times.
✓ Branch 35 → 36 taken 3 times.
✓ Branch 36 → 37 taken 3 times.
✓ Branch 39 → 40 taken 3 times.
✓ Branch 39 → 41 taken 2 times.
✓ Branch 41 → 42 taken 3 times.
✓ Branch 41 → 43 taken 2 times.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
5 ? parseLevelName(parser.value(QString::fromLatin1(kOptLogLevel)))
60 : Info;
61
9/12
✓ Branch 45 → 46 taken 5 times.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 52 taken 4 times.
✓ Branch 48 → 49 taken 1 time.
✓ Branch 50 → 51 taken 1 time.
✗ Branch 50 → 52 not taken.
✓ Branch 53 → 54 taken 1 time.
✓ Branch 53 → 55 taken 4 times.
✓ Branch 55 → 56 taken 1 time.
✓ Branch 55 → 60 taken 4 times.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
5 } else if (const QByteArray envRules = qgetenv(kEnvLogRules); !envRules.isNull() && !envRules.trimmed().isEmpty()) {
62
1/1
✓ Branch 56 → 57 taken 1 time.
1 customRules = QString::fromUtf8(envRules);
63
3/3
✓ Branch 60 → 61 taken 4 times.
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 67 taken 3 times.
4 } else if (const QByteArray envLevel = qgetenv(kEnvLogLevel); !envLevel.isNull()) {
64
2/2
✓ Branch 63 → 64 taken 1 time.
✓ Branch 64 → 65 taken 1 time.
1 level = parseLevelName(QString::fromUtf8(envLevel));
65 9 }
66
67
1/1
✓ Branch 71 → 72 taken 11 times.
11 const QString rules = composeRules(level, customRules);
68
1/1
✓ Branch 72 → 73 taken 11 times.
11 QLoggingCategory::setFilterRules(rules);
69 11 return rules;
70 11 }
71
72 LogConfigurator::Level
73 26 LogConfigurator::parseLevelName(const QString &name) {
74
2/2
✓ Branch 2 → 3 taken 26 times.
✓ Branch 3 → 4 taken 26 times.
26 const QString normalized = name.trimmed().toLower();
75
12/14
✓ Branch 9 → 10 taken 23 times.
✓ Branch 9 → 15 taken 3 times.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 22 times.
✓ Branch 17 → 18 taken 23 times.
✓ Branch 17 → 19 taken 3 times.
✓ Branch 19 → 20 taken 23 times.
✓ Branch 19 → 21 taken 3 times.
✓ Branch 21 → 22 taken 26 times.
✗ Branch 21 → 23 not taken.
✓ Branch 23 → 24 taken 26 times.
✗ Branch 23 → 25 not taken.
✓ Branch 25 → 26 taken 4 times.
✓ Branch 25 → 27 taken 22 times.
75 if (normalized == QStringLiteral("off") || normalized == QStringLiteral("none"))
76 4 return Off;
77
5/6
✓ Branch 36 → 37 taken 17 times.
✓ Branch 36 → 47 taken 1 time.
✓ Branch 63 → 64 taken 22 times.
✗ Branch 63 → 65 not taken.
✓ Branch 65 → 66 taken 6 times.
✓ Branch 65 → 67 taken 16 times.
62 if (normalized == QStringLiteral("error") ||
78
4/6
✓ Branch 41 → 42 taken 17 times.
✗ Branch 41 → 47 not taken.
✓ Branch 59 → 60 taken 18 times.
✓ Branch 59 → 61 taken 4 times.
✓ Branch 61 → 62 taken 22 times.
✗ Branch 61 → 63 not taken.
57 normalized == QStringLiteral("critical") ||
79
8/8
✓ Branch 31 → 32 taken 18 times.
✓ Branch 31 → 47 taken 4 times.
✓ Branch 46 → 47 taken 1 time.
✓ Branch 46 → 48 taken 16 times.
✓ Branch 55 → 56 taken 17 times.
✓ Branch 55 → 57 taken 5 times.
✓ Branch 57 → 58 taken 18 times.
✓ Branch 57 → 59 taken 4 times.
101 normalized == QStringLiteral("err") ||
80
6/6
✓ Branch 49 → 50 taken 17 times.
✓ Branch 49 → 51 taken 5 times.
✓ Branch 51 → 52 taken 17 times.
✓ Branch 51 → 53 taken 5 times.
✓ Branch 53 → 54 taken 17 times.
✓ Branch 53 → 55 taken 5 times.
39 normalized == QStringLiteral("fatal"))
81 6 return Error;
82
7/8
✓ Branch 71 → 72 taken 13 times.
✓ Branch 71 → 77 taken 3 times.
✓ Branch 76 → 77 taken 1 time.
✓ Branch 76 → 78 taken 12 times.
✓ Branch 85 → 86 taken 16 times.
✗ Branch 85 → 87 not taken.
✓ Branch 87 → 88 taken 4 times.
✓ Branch 87 → 89 taken 12 times.
61 if (normalized == QStringLiteral("warning") ||
83
5/6
✓ Branch 79 → 80 taken 13 times.
✓ Branch 79 → 81 taken 3 times.
✓ Branch 81 → 82 taken 13 times.
✓ Branch 81 → 83 taken 3 times.
✓ Branch 83 → 84 taken 16 times.
✗ Branch 83 → 85 not taken.
29 normalized == QStringLiteral("warn"))
84 4 return Warning;
85
2/2
✓ Branch 95 → 96 taken 3 times.
✓ Branch 95 → 97 taken 9 times.
12 if (normalized == QStringLiteral("info"))
86 3 return Info;
87
5/6
✓ Branch 106 → 107 taken 4 times.
✓ Branch 106 → 112 taken 1 time.
✓ Branch 124 → 125 taken 9 times.
✗ Branch 124 → 126 not taken.
✓ Branch 126 → 127 taken 6 times.
✓ Branch 126 → 128 taken 3 times.
23 if (normalized == QStringLiteral("debug") ||
88
7/8
✓ Branch 101 → 102 taken 5 times.
✓ Branch 101 → 112 taken 4 times.
✓ Branch 111 → 112 taken 1 time.
✓ Branch 111 → 113 taken 3 times.
✓ Branch 120 → 121 taken 5 times.
✓ Branch 120 → 122 taken 4 times.
✓ Branch 122 → 123 taken 9 times.
✗ Branch 122 → 124 not taken.
37 normalized == QStringLiteral("trace") ||
89
6/6
✓ Branch 114 → 115 taken 4 times.
✓ Branch 114 → 116 taken 5 times.
✓ Branch 116 → 117 taken 4 times.
✓ Branch 116 → 118 taken 5 times.
✓ Branch 118 → 119 taken 5 times.
✓ Branch 118 → 120 taken 4 times.
13 normalized == QStringLiteral("all"))
90 6 return Debug;
91 // Unrecognized → project default.
92 3 return Error;
93 26 }
94
95 20 QString LogConfigurator::levelName(LogConfigurator::Level level) {
96
5/6
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 8 taken 5 times.
✓ Branch 2 → 13 taken 4 times.
✓ Branch 2 → 18 taken 4 times.
✓ Branch 2 → 23 taken 4 times.
✗ Branch 2 → 28 not taken.
20 switch (level) {
97 3 case Off:
98 3 return QStringLiteral("off");
99 5 case Error:
100 5 return QStringLiteral("error");
101 4 case Warning:
102 4 return QStringLiteral("warning");
103 4 case Info:
104 4 return QStringLiteral("info");
105 4 case Debug:
106 4 return QStringLiteral("debug");
107 }
108 ✗ return QStringLiteral("error");
109 }
110
111 23 QString LogConfigurator::rulesForLevel(LogConfigurator::Level level) {
112 // Qt's default rules: *.debug=false, *.info=false (warnings+criticals on).
113 // We only ever constrain mailjd.* so Qt's own warnings stay visible.
114
5/6
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 8 taken 9 times.
✓ Branch 2 → 13 taken 2 times.
✓ Branch 2 → 18 taken 6 times.
✓ Branch 2 → 23 taken 3 times.
✗ Branch 2 → 28 not taken.
23 switch (level) {
115 3 case Off:
116 // Silence every mailjd.* category at every level.
117 3 return QStringLiteral("mailjd.*=false\n");
118 9 case Error:
119 // Default: only qCCritical(lc...) reaches the output.
120 9 return QStringLiteral("mailjd.*.debug=false\n"
121 "mailjd.*.info=false\n"
122 "mailjd.*.warning=false\n");
123 2 case Warning:
124 // Qt default behaviour for mailjd.* (explicit).
125 2 return QStringLiteral("mailjd.*.debug=false\n"
126 "mailjd.*.info=false\n");
127 6 case Info:
128 6 return QStringLiteral("mailjd.*.debug=false\n"
129 "mailjd.*.info=true\n");
130 3 case Debug:
131 3 return QStringLiteral("mailjd.*.debug=true\n"
132 "mailjd.*.info=true\n");
133 }
134 ✗ return QStringLiteral("mailjd.*.warning=false\n");
135 }
136
137 15 QString LogConfigurator::composeRules(LogConfigurator::Level level,
138 const QString &customRules) {
139
3/3
✓ Branch 2 → 3 taken 15 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 11 times.
15 if (!customRules.trimmed().isEmpty())
140 4 return customRules.trimmed();
141 11 return rulesForLevel(level);
142 }
143