QtBase  v6.3.1
tst_qloggingregistry.cpp
Go to the documentation of this file.
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 <QTest>
30 #include <QLoggingCategory>
31 #include <QStandardPaths>
32 
33 #include <QtCore/private/qloggingregistry_p.h>
34 
39  NoMatch
40 };
43 
45 {
46  Q_OBJECT
47 
48 private slots:
49 
50  void initTestCase()
51  {
52  // ensure a clean environment
54  qputenv("XDG_CONFIG_DIRS", "/does/not/exist");
55  qunsetenv("QT_LOGGING_CONF");
56  qunsetenv("QT_LOGGING_RULES");
57  }
58 
59  void QLoggingRule_parse_data()
60  {
61  QTest::addColumn<QString>("pattern");
62  QTest::addColumn<QString>("category");
63  QTest::addColumn<QtMsgType>("msgType");
64  QTest::addColumn<LoggingRuleState>("result");
65 
66  // _empty_ should match (only) _empty_
67  QTest::newRow("_empty_-_empty_")
68  << QString("") << QString("") << QtDebugMsg << Match;
69  QTest::newRow("_empty_-default")
70  << QString("") << QString("default") << QtDebugMsg << NoMatch;
71  QTest::newRow(".debug-_empty_")
72  << QString(".debug") << QString("") << QtDebugMsg << Match;
73  QTest::newRow(".warning-default")
74  << QString(".warning") << QString("default") << QtDebugMsg << NoMatch;
75 
76  // literal should match only literal
77  QTest::newRow("qt-qt")
78  << QString("qt") << QString("qt") << QtDebugMsg << Match;
79  QTest::newRow("qt-_empty_")
80  << QString("qt") << QString("") << QtDebugMsg << NoMatch;
81  QTest::newRow("qt-qtx")
82  << QString("qt") << QString("qtx") << QtDebugMsg << NoMatch;
83  QTest::newRow("qt-qt.io")
84  << QString("qt") << QString("qt.io") << QtDebugMsg << NoMatch;
85  QTest::newRow("qt.debug-qt")
86  << QString("qt.debug") << QString("qt") << QtDebugMsg << Match;
87  QTest::newRow("qt.critical-qt")
88  << QString("qt.critical") << QString("qt") << QtDebugMsg << NoMatch;
89 
90  // * should match everything
91  QTest::newRow("_star_-qt.io.debug")
92  << QString("*") << QString("qt.io") << QtDebugMsg << Match;
93  QTest::newRow("_star_-qt.io.warning")
94  << QString("*") << QString("qt.io") << QtWarningMsg << Match;
95  QTest::newRow("_star_-qt.io.critical")
96  << QString("*") << QString("qt.io") << QtCriticalMsg << Match;
97  QTest::newRow("_star_-_empty_")
98  << QString("*") << QString("") << QtDebugMsg << Match;
99  QTest::newRow("_star_.debug-qt.io")
100  << QString("*.debug") << QString("qt.io") << QtDebugMsg << Match;
101  QTest::newRow("_star_.warning-qt.io")
102  << QString("*.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
103 
104  // qt.* should match everything starting with 'qt.'
105  QTest::newRow("qt._star_-qt.io")
106  << QString("qt.*") << QString("qt.io") << QtDebugMsg << Match;
107  QTest::newRow("qt._star_-qt")
108  << QString("qt.*") << QString("qt") << QtDebugMsg << NoMatch;
109  QTest::newRow("qt__star_-qt")
110  << QString("qt*") << QString("qt") << QtDebugMsg << Match;
111  QTest::newRow("qt._star_-qt.io.fs")
112  << QString("qt.*") << QString("qt.io.fs") << QtDebugMsg << Match;
113  QTest::newRow("qt._star_.debug-qt.io.fs")
114  << QString("qt.*.debug") << QString("qt.io.fs") << QtDebugMsg << Match;
115  QTest::newRow("qt._star_.warning-qt.io.fs")
116  << QString("qt.*.warning") << QString("qt.io.fs") << QtDebugMsg << NoMatch;
117 
118  // *.io should match everything ending with .io
119  QTest::newRow("_star_.io-qt.io")
120  << QString("*.io") << QString("qt.io") << QtDebugMsg << Match;
121  QTest::newRow("_star_io-qt.io")
122  << QString("*io") << QString("qt.io") << QtDebugMsg << Match;
123  QTest::newRow("_star_.io-io")
124  << QString("*.io") << QString("io") << QtDebugMsg << NoMatch;
125  QTest::newRow("_star_io-io")
126  << QString("*io") << QString("io") << QtDebugMsg << Match;
127  QTest::newRow("_star_.io-qt.ios")
128  << QString("*.io") << QString("qt.ios") << QtDebugMsg << NoMatch;
129  QTest::newRow("_star_.io-qt.io.x")
130  << QString("*.io") << QString("qt.io.x") << QtDebugMsg << NoMatch;
131  QTest::newRow("_star_.io.debug-qt.io")
132  << QString("*.io.debug") << QString("qt.io") << QtDebugMsg << Match;
133  QTest::newRow("_star_.io.warning-qt.io")
134  << QString("*.io.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
135 
136  // *qt* should match everything that contains 'qt'
137  QTest::newRow("_star_qt_star_-qt.core.io")
138  << QString("*qt*") << QString("qt.core.io") << QtDebugMsg << Match;
139  QTest::newRow("_star_qt_star_-default")
140  << QString("*qt*") << QString("default") << QtDebugMsg << NoMatch;
141  QTest::newRow("_star_qt._star_.debug-qt.io")
142  << QString("*qt.*.debug") << QString("qt.io") << QtDebugMsg << Match;
143  QTest::newRow("_star_.qt._star_.warning-qt.io")
144  << QString("*.qt.*.warning") << QString("qt.io") << QtDebugMsg << NoMatch;
145  QTest::newRow("**")
146  << QString("**") << QString("qt.core.io") << QtDebugMsg << Match;
147 
148  // * outside of start/end
149  QTest::newRow("qt.*.io")
150  << QString("qt.*.io") << QString("qt.core.io") << QtDebugMsg << Invalid;
151  QTest::newRow("***")
152  << QString("***") << QString("qt.core.io") << QtDebugMsg << Invalid;
153  }
154 
155  void QLoggingRule_parse()
156  {
159  QFETCH(QtMsgType, msgType);
161 
162  const auto categoryL1 = category.toLatin1();
163  const auto categoryL1S = QLatin1String(categoryL1);
164 
165  QLoggingRule rule(pattern, true);
167  if (rule.flags != 0) {
168  switch (rule.pass(categoryL1S, msgType)) {
169  case -1: QFAIL("Shoudn't happen, we set pattern to true"); break;
170  case 0: state = NoMatch; break;
171  case 1: state = Match; break;
172  }
173  }
175  }
176 
177  void QLoggingSettingsParser_iniStyle()
178  {
179  //
180  // Logging configuration can be described
181  // in an .ini file. [Rules] is the
182  // default category, and optional ...
183  //
185  parser.setContent(u"[Rules]\n"
186  "default=false\n"
187  "default=true");
188  QCOMPARE(parser.rules().size(), 2);
189 
190  parser.setContent(u"[Rules]\n"
191  "default=false");
192  QCOMPARE(parser.rules().size(), 1);
193 
194  // QSettings escapes * to %2A when writing.
195  parser.setContent(u"[Rules]\n"
196  "module.%2A=false");
197  QCOMPARE(parser.rules().size(), 1);
198  QCOMPARE(parser.rules().first().category, QString("module."));
199  QCOMPARE(parser.rules().first().flags, QLoggingRule::LeftFilter);
200 
201  parser.setContent(u"[OtherSection]\n"
202  "default=false");
203  QCOMPARE(parser.rules().size(), 0);
204  }
205 
206  void QLoggingRegistry_environment()
207  {
208  //
209  // Check whether QT_LOGGING_CONF is picked up from environment
210  //
211 
212  Q_ASSERT(!qApp); // Rules should not require an app to resolve
213 
214  qputenv("QT_LOGGING_RULES", "qt.foo.bar=true");
215  QLoggingCategory qtEnabledByLoggingRule("qt.foo.bar");
216  QCOMPARE(qtEnabledByLoggingRule.isDebugEnabled(), true);
217  QLoggingCategory qtDisabledByDefault("qt.foo.baz");
218  QCOMPARE(qtDisabledByDefault.isDebugEnabled(), false);
219 
221  QCOMPARE(registry.ruleSets[QLoggingRegistry::ApiRules].size(), 0);
222  QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 0);
223  QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 1);
224 
225  qunsetenv("QT_LOGGING_RULES");
226  qputenv("QT_LOGGING_CONF", QFINDTESTDATA("qtlogging.ini").toLocal8Bit());
227  registry.initializeRules();
228 
229  QCOMPARE(registry.ruleSets[QLoggingRegistry::ApiRules].size(), 0);
230  QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 0);
231  QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 1);
232 
233  // check that QT_LOGGING_RULES take precedence
234  qputenv("QT_LOGGING_RULES", "Digia.*=true");
235  registry.initializeRules();
236  QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].size(), 2);
237  QCOMPARE(registry.ruleSets[QLoggingRegistry::EnvironmentRules].at(1).enabled, true);
238  }
239 
240  void QLoggingRegistry_config()
241  {
242  //
243  // Check whether QtProject/qtlogging.ini is loaded automatically
244  //
245 
246  // first try to create a test file..
248  QVERIFY(!path.isEmpty());
249  QDir dir(path + "/QtProject");
250  if (!dir.exists())
251  QVERIFY(dir.mkpath(path + "/QtProject"));
252 
253  QFile file(dir.absoluteFilePath("qtlogging.ini"));
255  QTextStream out(&file);
256  out << "[Rules]\n";
257  out << "Digia.*=false\n";
258  file.close();
259 
261  registry.initializeRules();
262  QCOMPARE(registry.ruleSets[QLoggingRegistry::ConfigRules].size(), 1);
263 
264  // remove file again
265  QVERIFY(file.remove());
266  }
267 
268  void QLoggingRegistry_rulePriorities()
269  {
270  //
271  // Rules can stem from 3 sources:
272  // via QLoggingCategory::setFilterRules (API)
273  // via qtlogging.ini file in settings (Config)
274  // via QT_LOGGING_CONF environment variable (Env)
275  //
276  // Rules set by environment should get higher precedence than qtlogging.conf,
277  // than QLoggingCategory::setFilterRules
278  //
279 
280  QLoggingCategory cat("Digia.Berlin");
282 
283  // empty all rules , check default
284  registry->ruleSets[QLoggingRegistry::ApiRules].clear();
285  registry->ruleSets[QLoggingRegistry::ConfigRules].clear();
286  registry->ruleSets[QLoggingRegistry::EnvironmentRules].clear();
287  registry->updateRules();
288 
289  QVERIFY(cat.isWarningEnabled());
290 
291  // set Config rule
293  parser.setContent(u"[Rules]\nDigia.*=false");
294  registry->ruleSets[QLoggingRegistry::ConfigRules] = parser.rules();
295  registry->updateRules();
296 
297  QVERIFY(!cat.isWarningEnabled());
298 
299  // set API rule, should overwrite API one
300  QLoggingCategory::setFilterRules("Digia.*=true");
301 
302  QVERIFY(cat.isWarningEnabled());
303 
304  // set Env rule, should overwrite Config one
305  parser.setContent(u"Digia.*=false");
306  registry->ruleSets[QLoggingRegistry::EnvironmentRules] = parser.rules();
307  registry->updateRules();
308 
309  QVERIFY(!cat.isWarningEnabled());
310  }
311 
312 
313  void QLoggingRegistry_checkErrors()
314  {
316  QTest::ignoreMessage(QtWarningMsg, "Ignoring malformed logging rule: '***=false'");
317  QTest::ignoreMessage(QtWarningMsg, "Ignoring malformed logging rule: '*=0'");
318  QTest::ignoreMessage(QtWarningMsg, "Ignoring malformed logging rule: '*=TRUE'");
319  parser.setContent(u"[Rules]\n"
320  "***=false\n"
321  "*=0\n"
322  "*=TRUE\n");
323  QVERIFY(parser.rules().isEmpty());
324  }
325 };
326 
328 
329 #include "tst_qloggingregistry.moc"
small capitals from c petite p scientific f u
Definition: afcover.h:88
const char ** registry
Definition: cffdrivr.c:696
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:55
void close() override
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool open(OpenMode flags) override
Definition: qfile.cpp:897
bool remove()
Definition: qfile.cpp:444
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QLoggingCategory class represents a category, or 'area' in the logging infrastructure.
static void setFilterRules(const QString &rules)
bool isWarningEnabled() const
bool isDebugEnabled() const
static QLoggingRegistry * instance()
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
static void setTestModeEnabled(bool testMode)
static QString writableLocation(StandardLocation type)
The QString class provides a Unicode character string.
Definition: qstring.h:388
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:62
const QLoggingCategory & category()
[1]
QCOMPARE(spy.count(), 1)
else opt state
[0]
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Definition: qtestcase.cpp:2658
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message)
Definition: qtestcase.cpp:2292
parser
Definition: devices.py:74
#define QString()
Definition: parse-defines.h:51
#define qApp
DBusConnection const char * rule
QtMsgType
Definition: qlogging.h:60
@ QtCriticalMsg
Definition: qlogging.h:63
@ QtWarningMsg
Definition: qlogging.h:62
@ QtDebugMsg
Definition: qlogging.h:61
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLubyte * pattern
Definition: qopenglext.h:2744
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define QTEST_APPLESS_MAIN(TestObject)
Definition: qtest.h:632
#define QFETCH(Type, name)
Definition: qtestcase.h:230
#define QFAIL(message)
Definition: qtestcase.h:70
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QFINDTESTDATA(basepath)
Definition: qtestcase.h:251
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
QFile file
[0]
QTextStream out(stdout)
[7]
QString dir
[11]
Q_DECLARE_METATYPE(LoggingRuleState)