1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest>
30#include <QLoggingCategory>
31
32#include <QtCore/private/qloggingregistry_p.h>
33
34QT_USE_NAMESPACE
35enum LoggingRuleState {
36 Invalid,
37 Match,
38 NoMatch
39};
40Q_DECLARE_METATYPE(LoggingRuleState);
41Q_DECLARE_METATYPE(QtMsgType);
42
43class tst_QLoggingRegistry : public QObject
44{
45 Q_OBJECT
46
47private slots:
48
49 void initTestCase()
50 {
51 // ensure a clean environment
52 QStandardPaths::setTestModeEnabled(true);
53 qputenv(varName: "XDG_CONFIG_DIRS", value: "/does/not/exist");
54 qunsetenv(varName: "QT_LOGGING_CONF");
55 qunsetenv(varName: "QT_LOGGING_RULES");
56 }
57
58 void QLoggingRule_parse_data()
59 {
60 QTest::addColumn<QString>(name: "pattern");
61 QTest::addColumn<QString>(name: "category");
62 QTest::addColumn<QtMsgType>(name: "msgType");
63 QTest::addColumn<LoggingRuleState>(name: "result");
64
65 // _empty_ should match (only) _empty_
66 QTest::newRow(dataTag: "_empty_-_empty_")
67 << QString("") << QString("") << QtDebugMsg << Match;
68 QTest::newRow(dataTag: "_empty_-default")
69 << QString("") << QString("default") << QtDebugMsg << NoMatch;
70 QTest::newRow(dataTag: ".debug-_empty_")
71 << QString(".debug") << QString("") << QtDebugMsg << Match;
72 QTest::newRow(dataTag: ".warning-default")
73 << QString(".warning") << QString("default") << QtDebugMsg << NoMatch;
74
75 // literal should match only literal
76 QTest::newRow(dataTag: "qt-qt")
77 << QString("qt") << QString("qt") << QtDebugMsg << Match;
78 QTest::newRow(dataTag: "qt-_empty_")
79 << QString("qt") << QString("") << QtDebugMsg << NoMatch;
80 QTest::newRow(dataTag: "qt-qtx")
81 << QString("qt") << QString("qtx") << QtDebugMsg << NoMatch;
82 QTest::newRow(dataTag: "qt-qt.io")
83 << QString("qt") << QString("qt.io") << QtDebugMsg << NoMatch;
84 QTest::newRow(dataTag: "qt.debug-qt")
85 << QString("qt.debug") << QString("qt") << QtDebugMsg << Match;
86 QTest::newRow(dataTag: "qt.critical-qt")
87 << QString("qt.critical") << QString("qt") << QtDebugMsg << NoMatch;
88
89 // * should match everything
90 QTest::newRow(dataTag: "_star_-qt.io.debug")
91 << QString("*") << QString("qt.io") << QtDebugMsg << Match;
92 QTest::newRow(dataTag: "_star_-qt.io.warning")
93 << QString("*") << QString("qt.io") << QtWarningMsg << Match;
94 QTest::newRow(dataTag: "_star_-qt.io.critical")
95 << QString("*") << QString("qt.io") << QtCriticalMsg << Match;
96 QTest::newRow(dataTag: "_star_-_empty_")
97 << QString("*") << QString("") << QtDebugMsg << Match;
98 QTest::newRow(dataTag: "_star_.debug-qt.io")
99 << QString("*.debug") << QString("qt.io") << QtDebugMsg << Match;
100 QTest::newRow(dataTag: "_star_.warning-qt.io")
101 << QString("*.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
102
103 // qt.* should match everything starting with 'qt.'
104 QTest::newRow(dataTag: "qt._star_-qt.io")
105 << QString("qt.*") << QString("qt.io") << QtDebugMsg << Match;
106 QTest::newRow(dataTag: "qt._star_-qt")
107 << QString("qt.*") << QString("qt") << QtDebugMsg << NoMatch;
108 QTest::newRow(dataTag: "qt__star_-qt")
109 << QString("qt*") << QString("qt") << QtDebugMsg << Match;
110 QTest::newRow(dataTag: "qt._star_-qt.io.fs")
111 << QString("qt.*") << QString("qt.io.fs") << QtDebugMsg << Match;
112 QTest::newRow(dataTag: "qt._star_.debug-qt.io.fs")
113 << QString("qt.*.debug") << QString("qt.io.fs") << QtDebugMsg << Match;
114 QTest::newRow(dataTag: "qt._star_.warning-qt.io.fs")
115 << QString("qt.*.warning") << QString("qt.io.fs") << QtDebugMsg << NoMatch;
116
117 // *.io should match everything ending with .io
118 QTest::newRow(dataTag: "_star_.io-qt.io")
119 << QString("*.io") << QString("qt.io") << QtDebugMsg << Match;
120 QTest::newRow(dataTag: "_star_io-qt.io")
121 << QString("*io") << QString("qt.io") << QtDebugMsg << Match;
122 QTest::newRow(dataTag: "_star_.io-io")
123 << QString("*.io") << QString("io") << QtDebugMsg << NoMatch;
124 QTest::newRow(dataTag: "_star_io-io")
125 << QString("*io") << QString("io") << QtDebugMsg << Match;
126 QTest::newRow(dataTag: "_star_.io-qt.ios")
127 << QString("*.io") << QString("qt.ios") << QtDebugMsg << NoMatch;
128 QTest::newRow(dataTag: "_star_.io-qt.io.x")
129 << QString("*.io") << QString("qt.io.x") << QtDebugMsg << NoMatch;
130 QTest::newRow(dataTag: "_star_.io.debug-qt.io")
131 << QString("*.io.debug") << QString("qt.io") << QtDebugMsg << Match;
132 QTest::newRow(dataTag: "_star_.io.warning-qt.io")
133 << QString("*.io.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
134
135 // *qt* should match everything that contains 'qt'
136 QTest::newRow(dataTag: "_star_qt_star_-qt.core.io")
137 << QString("*qt*") << QString("qt.core.io") << QtDebugMsg << Match;
138 QTest::newRow(dataTag: "_star_qt_star_-default")
139 << QString("*qt*") << QString("default") << QtDebugMsg << NoMatch;
140 QTest::newRow(dataTag: "_star_qt._star_.debug-qt.io")
141 << QString("*qt.*.debug") << QString("qt.io") << QtDebugMsg << Match;
142 QTest::newRow(dataTag: "_star_.qt._star_.warning-qt.io")
143 << QString("*.qt.*.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
144 QTest::newRow(dataTag: "**")
145 << QString("**") << QString("qt.core.io") << QtDebugMsg << Match;
146
147 // * outside of start/end
148 QTest::newRow(dataTag: "qt.*.io")
149 << QString("qt.*.io") << QString("qt.core.io") << QtDebugMsg << Invalid;
150 QTest::newRow(dataTag: "***")
151 << QString("***") << QString("qt.core.io") << QtDebugMsg << Invalid;
152 }
153
154 void QLoggingRule_parse()
155 {
156 QFETCH(QString, pattern);
157 QFETCH(QString, category);
158 QFETCH(QtMsgType, msgType);
159 QFETCH(LoggingRuleState, result);
160
161 const auto categoryL1 = category.toLatin1();
162 const auto categoryL1S = QLatin1String(categoryL1);
163
164 QLoggingRule rule(pattern, true);
165 LoggingRuleState state = Invalid;
166 if (rule.flags != 0) {
167 switch (rule.pass(categoryName: categoryL1S, type: msgType)) {
168 case -1: QFAIL("Shoudn't happen, we set pattern to true"); break;
169 case 0: state = NoMatch; break;
170 case 1: state = Match; break;
171 }
172 }
173 QCOMPARE(state, result);
174 }
175
176 void QLoggingSettingsParser_iniStyle()
177 {
178 //
179 // Logging configuration can be described
180 // in an .ini file. [Rules] is the
181 // default category, and optional ...
182 //
183 QLoggingSettingsParser parser;
184 parser.setContent("[Rules]\n"
185 "default=false\n"
186 "default=true");
187 QCOMPARE(parser.rules().size(), 2);
188
189 parser.setContent("[Rules]\n"
190 "default=false");
191 QCOMPARE(parser.rules().size(), 1);
192
193 // QSettings escapes * to %2A when writing.
194 parser.setContent("[Rules]\n"
195 "module.%2A=false");
196 QCOMPARE(parser.rules().size(), 1);
197 QCOMPARE(parser.rules().first().category, QString("module."));
198 QCOMPARE(parser.rules().first().flags, QLoggingRule::LeftFilter);
199
200 parser.setContent("[OtherSection]\n"
201 "default=false");
202 QCOMPARE(parser.rules().size(), 0);
203 }
204
205 void QLoggingRegistry_environment()
206 {
207 //
208 // Check whether QT_LOGGING_CONF is picked up from environment
209 //
210
211 Q_ASSERT(!qApp); // Rules should not require an app to resolve
212
213 qputenv(varName: "QT_LOGGING_RULES", value: "qt.foo.bar=true");
214 QLoggingCategory qtEnabledByLoggingRule("qt.foo.bar");
215 QCOMPARE(qtEnabledByLoggingRule.isDebugEnabled(), true);
216 QLoggingCategory qtDisabledByDefault("qt.foo.baz");
217 QCOMPARE(qtDisabledByDefault.isDebugEnabled(), false);
218
219 QLoggingRegistry &registry = *QLoggingRegistry::instance();
220 QCOMPARE(registry.ruleSets[QLoggingRegistry::ApiRules].size(), 0);
221 QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 0);
222 QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 1);
223
224 qunsetenv(varName: "QT_LOGGING_RULES");
225 qputenv(varName: "QT_LOGGING_CONF", QFINDTESTDATA("qtlogging.ini").toLocal8Bit());
226 registry.initializeRules();
227
228 QCOMPARE(registry.ruleSets[QLoggingRegistry::ApiRules].size(), 0);
229 QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 0);
230 QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 1);
231
232 // check that QT_LOGGING_RULES take precedence
233 qputenv(varName: "QT_LOGGING_RULES", value: "Digia.*=true");
234 registry.initializeRules();
235 QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 2);
236 QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].at(1).enabled, true);
237 }
238
239 void QLoggingRegistry_config()
240 {
241 //
242 // Check whether QtProject/qtlogging.ini is loaded automatically
243 //
244
245 // first try to create a test file..
246 QString path = QStandardPaths::writableLocation(type: QStandardPaths::GenericConfigLocation);
247 QVERIFY(!path.isEmpty());
248 QDir dir(path + "/QtProject");
249 if (!dir.exists())
250 QVERIFY(dir.mkpath(path + "/QtProject"));
251
252 QFile file(dir.absoluteFilePath(fileName: "qtlogging.ini"));
253 QVERIFY(file.open(QFile::WriteOnly | QFile::Text));
254 QTextStream out(&file);
255 out << "[Rules]\n";
256 out << "Digia.*=false\n";
257 file.close();
258
259 QLoggingRegistry registry;
260 registry.initializeRules();
261 QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 1);
262
263 // remove file again
264 QVERIFY(file.remove());
265 }
266
267 void QLoggingRegistry_rulePriorities()
268 {
269 //
270 // Rules can stem from 3 sources:
271 // via QLoggingCategory::setFilterRules (API)
272 // via qtlogging.ini file in settings (Config)
273 // via QT_LOGGING_CONF environment variable (Env)
274 //
275 // Rules set by environment should get higher precedence than qtlogging.conf,
276 // than QLoggingCategory::setFilterRules
277 //
278
279 QLoggingCategory cat("Digia.Berlin");
280 QLoggingRegistry *registry = QLoggingRegistry::instance();
281
282 // empty all rules , check default
283 registry->ruleSets[QLoggingRegistry::ApiRules].clear();
284 registry->ruleSets[QLoggingRegistry::ConfigRules].clear();
285 registry->ruleSets[QLoggingRegistry::EnvironmentRules].clear();
286 registry->updateRules();
287
288 QVERIFY(cat.isWarningEnabled());
289
290 // set Config rule
291 QLoggingSettingsParser parser;
292 parser.setContent("[Rules]\nDigia.*=false");
293 registry->ruleSets[QLoggingRegistry::ConfigRules] = parser.rules();
294 registry->updateRules();
295
296 QVERIFY(!cat.isWarningEnabled());
297
298 // set API rule, should overwrite API one
299 QLoggingCategory::setFilterRules("Digia.*=true");
300
301 QVERIFY(cat.isWarningEnabled());
302
303 // set Env rule, should overwrite Config one
304 parser.setContent("Digia.*=false");
305 registry->ruleSets[QLoggingRegistry::EnvironmentRules] = parser.rules();
306 registry->updateRules();
307
308 QVERIFY(!cat.isWarningEnabled());
309 }
310
311
312 void QLoggingRegistry_checkErrors()
313 {
314 QLoggingSettingsParser parser;
315 QTest::ignoreMessage(type: QtWarningMsg, message: "Ignoring malformed logging rule: '***=false'");
316 QTest::ignoreMessage(type: QtWarningMsg, message: "Ignoring malformed logging rule: '*=0'");
317 QTest::ignoreMessage(type: QtWarningMsg, message: "Ignoring malformed logging rule: '*=TRUE'");
318 parser.setContent("[Rules]\n"
319 "***=false\n"
320 "*=0\n"
321 "*=TRUE\n");
322 QVERIFY(parser.rules().isEmpty());
323 }
324};
325
326QTEST_APPLESS_MAIN(tst_QLoggingRegistry)
327
328#include "tst_qloggingregistry.moc"
329

source code of qtbase/tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp