1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30
31#include <QtCore/QCoreApplication>
32#include <QtCore/QtDebug>
33#include <QtTest/QtTest>
34
35#include <QtConcurrentRun>
36#include <QFutureSynchronizer>
37
38class tst_QDebug: public QObject
39{
40 Q_OBJECT
41public:
42 enum EnumType { EnumValue1 = 1, EnumValue2 = 2 };
43 enum FlagType { EnumFlag1 = 1, EnumFlag2 = 2 };
44 Q_ENUM(EnumType)
45 Q_DECLARE_FLAGS(Flags, FlagType)
46 Q_FLAG(Flags)
47
48private slots:
49 void assignment() const;
50 void warningWithoutDebug() const;
51 void criticalWithoutDebug() const;
52 void debugWithBool() const;
53 void debugSpaceHandling() const;
54 void debugNoQuotes() const;
55 void verbosity() const;
56 void stateSaver() const;
57 void veryLongWarningMessage() const;
58 void qDebugQChar() const;
59 void qDebugQString() const;
60 void qDebugQStringRef() const;
61 void qDebugQStringView() const;
62 void qDebugQLatin1String() const;
63 void qDebugQByteArray() const;
64 void qDebugQFlags() const;
65 void textStreamModifiers() const;
66 void resetFormat() const;
67 void defaultMessagehandler() const;
68 void threadSafety() const;
69};
70
71void tst_QDebug::assignment() const
72{
73 QDebug debug1(QtDebugMsg);
74 QDebug debug2(QtWarningMsg);
75
76 QTest::ignoreMessage(type: QtDebugMsg, message: "foo");
77 QTest::ignoreMessage(type: QtWarningMsg, message: "bar 1 2");
78
79 debug1 << "foo";
80 debug2 << "bar";
81 debug1 = debug2;
82 debug1 << "1";
83 debug2 << "2";
84}
85
86static QtMsgType s_msgType;
87static QString s_msg;
88static QByteArray s_file;
89static int s_line;
90static QByteArray s_function;
91
92static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
93{
94 s_msg = msg;
95 s_msgType = type;
96 s_file = context.file;
97 s_line = context.line;
98 s_function = context.function;
99}
100
101// Helper class to ensure that the testlib message handler gets
102// restored at the end of each test function, even if the test
103// fails or throws an exception.
104class MessageHandlerSetter
105{
106public:
107 MessageHandlerSetter(QtMessageHandler newMessageHandler)
108 : oldMessageHandler(qInstallMessageHandler(newMessageHandler))
109 { }
110
111 ~MessageHandlerSetter()
112 {
113 qInstallMessageHandler(oldMessageHandler);
114 }
115
116private:
117 QtMessageHandler oldMessageHandler;
118};
119
120/*! \internal
121 The qWarning() stream should be usable even if QT_NO_DEBUG is defined.
122 */
123void tst_QDebug::warningWithoutDebug() const
124{
125 QString file, function;
126 int line = 0;
127 MessageHandlerSetter mhs(myMessageHandler);
128 { qWarning() << "A qWarning() message"; }
129#ifndef QT_NO_MESSAGELOGCONTEXT
130 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
131#endif
132 QCOMPARE(s_msgType, QtWarningMsg);
133 QCOMPARE(s_msg, QString::fromLatin1("A qWarning() message"));
134 QCOMPARE(QString::fromLatin1(s_file), file);
135 QCOMPARE(s_line, line);
136 QCOMPARE(QString::fromLatin1(s_function), function);
137}
138
139/*! \internal
140 The qCritical() stream should be usable even if QT_NO_DEBUG is defined.
141 */
142void tst_QDebug::criticalWithoutDebug() const
143{
144 QString file, function;
145 int line = 0;
146 MessageHandlerSetter mhs(myMessageHandler);
147 { qCritical() << "A qCritical() message"; }
148#ifndef QT_NO_MESSAGELOGCONTEXT
149 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
150#endif
151 QCOMPARE(s_msgType, QtCriticalMsg);
152 QCOMPARE(s_msg, QString::fromLatin1("A qCritical() message"));
153 QCOMPARE(QString::fromLatin1(s_file), file);
154 QCOMPARE(s_line, line);
155 QCOMPARE(QString::fromLatin1(s_function), function);
156}
157
158void tst_QDebug::debugWithBool() const
159{
160 QString file, function;
161 int line = 0;
162 MessageHandlerSetter mhs(myMessageHandler);
163 { qDebug() << false << true; }
164#ifndef QT_NO_MESSAGELOGCONTEXT
165 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
166#endif
167 QCOMPARE(s_msgType, QtDebugMsg);
168 QCOMPARE(s_msg, QString::fromLatin1("false true"));
169 QCOMPARE(QString::fromLatin1(s_file), file);
170 QCOMPARE(s_line, line);
171 QCOMPARE(QString::fromLatin1(s_function), function);
172}
173
174class MyPoint
175{
176public:
177 MyPoint(int val1, int val2)
178 : v1(val1), v2(val2) {}
179 int v1;
180 int v2;
181};
182QDebug operator<< (QDebug s, const MyPoint& point)
183{
184 const QDebugStateSaver saver(s);
185 s.nospace() << "MyPoint(" << point.v1 << ", " << point.v2 << ")";
186 return s;
187}
188
189class MyLine
190{
191public:
192 MyLine(const MyPoint& point1, const MyPoint& point2)
193 : p1(point1), p2(point2) {}
194 MyPoint p1;
195 MyPoint p2;
196};
197QDebug operator<< (QDebug s, const MyLine& line)
198{
199 const QDebugStateSaver saver(s);
200 s.nospace();
201 s << "MyLine(" << line.p1 << ", "<< line.p2;
202 if (s.verbosity() > 2)
203 s << ", Manhattan length=" << (qAbs(t: line.p2.v1 - line.p1.v1) + qAbs(t: line.p2.v2 - line.p1.v2));
204 s << ')';
205 return s;
206}
207
208void tst_QDebug::debugSpaceHandling() const
209{
210 MessageHandlerSetter mhs(myMessageHandler);
211 {
212 QDebug d = qDebug();
213 QVERIFY(d.autoInsertSpaces());
214 d.setAutoInsertSpaces(false);
215 QVERIFY(!d.autoInsertSpaces());
216 d << " ";
217 d.setAutoInsertSpaces(true);
218 QVERIFY(d.autoInsertSpaces());
219 d << "foo";
220 d.nospace();
221 d << "key=" << "value";
222 d.space();
223 d << 1 << 2;
224 MyLine line(MyPoint(10, 11), MyPoint (12, 13));
225 d << line;
226 d << "bar";
227 // With the old implementation of MyPoint doing dbg.nospace() << ...; dbg.space() we ended up with
228 // MyLine(MyPoint(10, 11) , MyPoint(12, 13) )
229 }
230 QCOMPARE(s_msg, QString::fromLatin1(" foo key=value 1 2 MyLine(MyPoint(10, 11), MyPoint(12, 13)) bar"));
231
232 QVERIFY(qDebug().autoInsertSpaces());
233 qDebug() << QPoint(21, 22) << QRect(23, 24, 25, 26) << QLine(27, 28, 29, 30);
234 QCOMPARE(s_msg, QString::fromLatin1("QPoint(21,22) QRect(23,24 25x26) QLine(QPoint(27,28),QPoint(29,30))"));
235 qDebug() << QPointF(21, 22) << QRectF(23, 24, 25, 26) << QLineF(27, 28, 29, 30);
236 QCOMPARE(s_msg, QString::fromLatin1("QPointF(21,22) QRectF(23,24 25x26) QLineF(QPointF(27,28),QPointF(29,30))"));
237 qDebug() << QMimeType() << QMimeDatabase().mimeTypeForName(nameOrAlias: "application/pdf") << "foo";
238 QCOMPARE(s_msg, QString::fromLatin1("QMimeType(invalid) QMimeType(\"application/pdf\") foo"));
239}
240
241void tst_QDebug::debugNoQuotes() const
242{
243 MessageHandlerSetter mhs(myMessageHandler);
244 {
245 QDebug d = qDebug();
246 d << QStringLiteral("Hello");
247 d.noquote();
248 d << QStringLiteral("Hello");
249 d.quote();
250 d << QStringLiteral("Hello");
251 }
252 QCOMPARE(s_msg, QString::fromLatin1("\"Hello\" Hello \"Hello\""));
253
254 {
255 QDebug d = qDebug();
256 d << QChar('H');
257 d << QLatin1String("Hello");
258 d << QByteArray("Hello");
259 d.noquote();
260 d << QChar('H');
261 d << QLatin1String("Hello");
262 d << QByteArray("Hello");
263 }
264 QCOMPARE(s_msg, QString::fromLatin1("'H' \"Hello\" \"Hello\" H Hello Hello"));
265}
266
267void tst_QDebug::verbosity() const
268{
269 MyLine line(MyPoint(10, 11), MyPoint (12, 13));
270 QString output;
271 QDebug d(&output);
272 d.nospace();
273 d << line << '\n';
274 const int oldVerbosity = d.verbosity();
275 d.setVerbosity(0);
276 QCOMPARE(d.verbosity(), 0);
277 d.setVerbosity(7);
278 QCOMPARE(d.verbosity(), 7);
279 const int newVerbosity = oldVerbosity + 2;
280 d.setVerbosity(newVerbosity);
281 QCOMPARE(d.verbosity(), newVerbosity);
282 d << line << '\n';
283 d.setVerbosity(oldVerbosity );
284 QCOMPARE(d.verbosity(), oldVerbosity );
285 d << line;
286 const QStringList lines = output.split(sep: QLatin1Char('\n'));
287 QCOMPARE(lines.size(), 3);
288 // Verbose should be longer
289 QVERIFY2(lines.at(1).size() > lines.at(0).size(), qPrintable(lines.join(QLatin1Char(','))));
290 // Switching back to brief produces same output
291 QCOMPARE(lines.at(0).size(), lines.at(2).size());
292}
293
294void tst_QDebug::stateSaver() const
295{
296 MessageHandlerSetter mhs(myMessageHandler);
297 {
298 QDebug d = qDebug();
299 d << 42;
300 {
301 QDebugStateSaver saver(d);
302 d << 43;
303 }
304 d << 44;
305 }
306 QCOMPARE(s_msg, QString::fromLatin1("42 43 44"));
307
308 {
309 QDebug d = qDebug();
310 {
311 QDebugStateSaver saver(d);
312 d.nospace() << Qt::hex << Qt::right << qSetFieldWidth(width: 3) << qSetPadChar(ch: '0') << 42;
313 }
314 d << 42;
315 }
316 QCOMPARE(s_msg, QString::fromLatin1("02a 42"));
317
318 {
319 QDebug d = qDebug();
320 {
321 QDebugStateSaver saver(d);
322 d.nospace().noquote() << QStringLiteral("Hello");
323 }
324 d << QStringLiteral("World");
325 }
326 QCOMPARE(s_msg, QString::fromLatin1("Hello \"World\""));
327
328 {
329 QDebug d = qDebug();
330 d.noquote().nospace() << QStringLiteral("Hello") << Qt::hex << 42;
331 {
332 QDebugStateSaver saver(d);
333 d.resetFormat();
334 d << QStringLiteral("World") << 42;
335 }
336 d << QStringLiteral("!") << 42;
337 }
338 QCOMPARE(s_msg, QString::fromLatin1("Hello2a\"World\" 42!2a"));
339}
340
341void tst_QDebug::veryLongWarningMessage() const
342{
343 QString file, function;
344 int line = 0;
345 MessageHandlerSetter mhs(myMessageHandler);
346 QString test;
347 {
348 QString part("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n");
349 for (int i = 0; i < 1000; ++i)
350 test.append(s: part);
351 qWarning(msg: "Test output:\n%s\nend", qPrintable(test));
352 }
353#ifndef QT_NO_MESSAGELOGCONTEXT
354 file = __FILE__; line = __LINE__ - 3; function = Q_FUNC_INFO;
355#endif
356 QCOMPARE(s_msgType, QtWarningMsg);
357 QCOMPARE(s_msg, QString::fromLatin1("Test output:\n")+test+QString::fromLatin1("\nend"));
358 QCOMPARE(QString::fromLatin1(s_file), file);
359 QCOMPARE(s_line, line);
360 QCOMPARE(QString::fromLatin1(s_function), function);
361}
362
363void tst_QDebug::qDebugQChar() const
364{
365 QString file, function;
366 int line = 0;
367 MessageHandlerSetter mhs(myMessageHandler);
368 {
369 QDebug d = qDebug();
370 d << QChar('f') << QChar(QLatin1Char('\xE4')); // f, ä
371 d.nospace().noquote() << QChar('o') << QChar('o') << QChar(QLatin1Char('\xC4')); // o, o, Ä
372 }
373#ifndef QT_NO_MESSAGELOGCONTEXT
374 file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
375#endif
376 QCOMPARE(s_msgType, QtDebugMsg);
377 QCOMPARE(s_msg, QString::fromLatin1("'f' '\\u00e4' oo\\u00c4"));
378 QCOMPARE(QString::fromLatin1(s_file), file);
379 QCOMPARE(s_line, line);
380 QCOMPARE(QString::fromLatin1(s_function), function);
381
382}
383
384void tst_QDebug::qDebugQString() const
385{
386 /* Use a basic string. */
387 {
388 QString file, function;
389 int line = 0;
390 const QString in(QLatin1String("input"));
391 const QStringRef inRef(&in);
392
393 MessageHandlerSetter mhs(myMessageHandler);
394 { qDebug() << inRef; }
395#ifndef QT_NO_MESSAGELOGCONTEXT
396 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
397#endif
398 QCOMPARE(s_msgType, QtDebugMsg);
399 QCOMPARE(s_msg, QString::fromLatin1("\"input\""));
400 QCOMPARE(QString::fromLatin1(s_file), file);
401 QCOMPARE(s_line, line);
402 QCOMPARE(QString::fromLatin1(s_function), function);
403 }
404
405 /* simpler tests from now on */
406 MessageHandlerSetter mhs(myMessageHandler);
407
408 QString string = "Hello";
409 qDebug() << string;
410 QCOMPARE(s_msg, QString("\"Hello\""));
411
412 qDebug().noquote().nospace() << string;
413 QCOMPARE(s_msg, string);
414
415 qDebug().noquote().nospace() << qSetFieldWidth(width: 8) << string;
416 QCOMPARE(s_msg, " " + string);
417
418 string = "Sm\xc3\xb8rg\xc3\xa5sbord " // Latin script
419 "\xce\x91\xce\xb8\xce\xae\xce\xbd\xce\xb1 " // Greek script
420 "\xd0\x9c\xd0\xbe\xd1\x81\xd0\xba\xd0\xb2\xd0\xb0"; // Cyrillic script
421 qDebug().noquote().nospace() << string;
422 QCOMPARE(s_msg, string);
423
424 // This string only contains printable characters
425 qDebug() << string;
426 QCOMPARE(s_msg, '"' + string + '"');
427
428 string = "\n\t\\\"";
429 qDebug().noquote().nospace() << string;
430 QCOMPARE(s_msg, string);
431
432 // This string only contains characters that must be escaped
433 qDebug() << string;
434 QCOMPARE(s_msg, QString("\"\\n\\t\\\\\\\"\""));
435
436 // Unicode escapes, BMP
437 string = "\1" // U+0001: START OF HEADING (category Cc)
438 "\x7f" // U+007F: DELETE (category Cc)
439 "\xc2\xad" // U+00AD: SOFT HYPHEN (category Cf)
440 "\xef\xbb\xbf"; // U+FEFF: ZERO WIDTH NO-BREAK SPACE / BOM (category Cf)
441 qDebug() << string;
442 QCOMPARE(s_msg, QString("\"\\u0001\\u007F\\u00AD\\uFEFF\""));
443
444 // Unicode printable non-BMP
445 string = "\xf0\x90\x80\x80"; // U+10000: LINEAR B SYLLABLE B008 A (category Lo)
446 qDebug() << string;
447 QCOMPARE(s_msg, '"' + string + '"');
448
449 // non-BMP and non-printable
450 string = "\xf3\xa0\x80\x81 " // U+E0001: LANGUAGE TAG (category Cf)
451 "\xf4\x80\x80\x80"; // U+100000: Plane 16 Private Use (category Co)
452 qDebug() << string;
453 QCOMPARE(s_msg, QString("\"\\U000E0001 \\U00100000\""));
454
455 // broken surrogate pairs
456 ushort utf16[] = { 0xDC00, 0xD800, 'x', 0xD800, 0 };
457 string = QString::fromUtf16(utf16);
458 qDebug() << string;
459 QCOMPARE(s_msg, QString("\"\\uDC00\\uD800x\\uD800\""));
460}
461
462void tst_QDebug::qDebugQStringRef() const
463{
464 /* Use a basic string. */
465 {
466 QString file, function;
467 int line = 0;
468 const QString in(QLatin1String("input"));
469 const QStringRef inRef(&in);
470
471 MessageHandlerSetter mhs(myMessageHandler);
472 { qDebug() << inRef; }
473#ifndef QT_NO_MESSAGELOGCONTEXT
474 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
475#endif
476 QCOMPARE(s_msgType, QtDebugMsg);
477 QCOMPARE(s_msg, QString::fromLatin1("\"input\""));
478 QCOMPARE(QString::fromLatin1(s_file), file);
479 QCOMPARE(s_line, line);
480 QCOMPARE(QString::fromLatin1(s_function), function);
481 }
482
483 /* Use a null QStringRef. */
484 {
485 QString file, function;
486 int line = 0;
487
488 const QStringRef inRef;
489
490 MessageHandlerSetter mhs(myMessageHandler);
491 { qDebug() << inRef; }
492#ifndef QT_NO_MESSAGELOGCONTEXT
493 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
494#endif
495 QCOMPARE(s_msgType, QtDebugMsg);
496 QCOMPARE(s_msg, QString::fromLatin1("\"\""));
497 QCOMPARE(QString::fromLatin1(s_file), file);
498 QCOMPARE(s_line, line);
499 QCOMPARE(QString::fromLatin1(s_function), function);
500 }
501}
502
503void tst_QDebug::qDebugQStringView() const
504{
505 /* Use a basic string. */
506 {
507 QLatin1String file, function;
508 int line = 0;
509 const QStringView inView = u"input";
510
511 MessageHandlerSetter mhs(myMessageHandler);
512 { qDebug() << inView; }
513#ifndef QT_NO_MESSAGELOGCONTEXT
514 file = QLatin1String(__FILE__); line = __LINE__ - 2; function = QLatin1String(Q_FUNC_INFO);
515#endif
516 QCOMPARE(s_msgType, QtDebugMsg);
517 QCOMPARE(s_msg, QLatin1String("\"input\""));
518 QCOMPARE(QLatin1String(s_file), file);
519 QCOMPARE(s_line, line);
520 QCOMPARE(QLatin1String(s_function), function);
521 }
522
523 /* Use a null QStringView. */
524 {
525 QString file, function;
526 int line = 0;
527
528 const QStringView inView;
529
530 MessageHandlerSetter mhs(myMessageHandler);
531 { qDebug() << inView; }
532#ifndef QT_NO_MESSAGELOGCONTEXT
533 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
534#endif
535 QCOMPARE(s_msgType, QtDebugMsg);
536 QCOMPARE(s_msg, QLatin1String("\"\""));
537 QCOMPARE(QLatin1String(s_file), file);
538 QCOMPARE(s_line, line);
539 QCOMPARE(QLatin1String(s_function), function);
540 }
541}
542
543void tst_QDebug::qDebugQLatin1String() const
544{
545 QString file, function;
546 int line = 0;
547 MessageHandlerSetter mhs(myMessageHandler);
548 {
549 QDebug d = qDebug();
550 d << QLatin1String("foo") << QLatin1String("") << QLatin1String("barbaz", 3);
551 d.nospace().noquote() << QLatin1String("baz");
552 }
553#ifndef QT_NO_MESSAGELOGCONTEXT
554 file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
555#endif
556 QCOMPARE(s_msgType, QtDebugMsg);
557 QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
558 QCOMPARE(QString::fromLatin1(s_file), file);
559 QCOMPARE(s_line, line);
560 QCOMPARE(QString::fromLatin1(s_function), function);
561
562 /* simpler tests from now on */
563 QLatin1String string("\"Hello\"");
564 qDebug() << string;
565 QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
566
567 qDebug().noquote().nospace() << string;
568 QCOMPARE(s_msg, QString(string));
569
570 qDebug().noquote().nospace() << qSetFieldWidth(width: 8) << string;
571 QCOMPARE(s_msg, " " + QString(string));
572
573 string = QLatin1String("\nSm\xF8rg\xE5sbord\\");
574 qDebug().noquote().nospace() << string;
575 QCOMPARE(s_msg, QString(string));
576
577 qDebug() << string;
578 QCOMPARE(s_msg, QString("\"\\nSm\\u00F8rg\\u00E5sbord\\\\\""));
579}
580
581void tst_QDebug::qDebugQByteArray() const
582{
583 QString file, function;
584 int line = 0;
585 MessageHandlerSetter mhs(myMessageHandler);
586 {
587 QDebug d = qDebug();
588 d << QByteArrayLiteral("foo") << QByteArrayLiteral("") << QByteArray("barbaz", 3);
589 d.nospace().noquote() << QByteArrayLiteral("baz");
590 }
591#ifndef QT_NO_MESSAGELOGCONTEXT
592 file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
593#endif
594 QCOMPARE(s_msgType, QtDebugMsg);
595 QCOMPARE(s_msg, QString::fromLatin1("\"foo\" \"\" \"bar\" baz"));
596 QCOMPARE(QString::fromLatin1(s_file), file);
597 QCOMPARE(s_line, line);
598 QCOMPARE(QString::fromLatin1(s_function), function);
599
600 /* simpler tests from now on */
601 QByteArray ba = "\"Hello\"";
602 qDebug() << ba;
603 QCOMPARE(s_msg, QString("\"\\\"Hello\\\"\""));
604
605 qDebug().noquote().nospace() << ba;
606 QCOMPARE(s_msg, QString::fromLatin1(ba));
607
608 qDebug().noquote().nospace() << qSetFieldWidth(width: 8) << ba;
609 QCOMPARE(s_msg, " " + QString::fromLatin1(ba));
610
611 ba = "\nSm\xC3\xB8rg\xC3\xA5sbord\\";
612 qDebug().noquote().nospace() << ba;
613 QCOMPARE(s_msg, QString::fromUtf8(ba));
614
615 qDebug() << ba;
616 QCOMPARE(s_msg, QString("\"\\nSm\\xC3\\xB8rg\\xC3\\xA5sbord\\\\\""));
617
618 // ensure that it closes hex escape sequences correctly
619 qDebug() << QByteArray("\377FFFF");
620 QCOMPARE(s_msg, QString("\"\\xFF\"\"FFFF\""));
621}
622
623enum TestEnum {
624 Flag1 = 0x1,
625 Flag2 = 0x10
626};
627
628Q_DECLARE_FLAGS(TestFlags, TestEnum)
629
630void tst_QDebug::qDebugQFlags() const
631{
632 QString file, function;
633 int line = 0;
634 QFlags<TestEnum> flags(Flag1 | Flag2);
635
636 MessageHandlerSetter mhs(myMessageHandler);
637 { qDebug() << flags; }
638#ifndef QT_NO_MESSAGELOGCONTEXT
639 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
640#endif
641 QCOMPARE(s_msgType, QtDebugMsg);
642 QCOMPARE(s_msg, QString::fromLatin1("QFlags(0x1|0x10)"));
643 QCOMPARE(QString::fromLatin1(s_file), file);
644 QCOMPARE(s_line, line);
645 QCOMPARE(QString::fromLatin1(s_function), function);
646
647 // Test the output of QFlags with an enum not declared with Q_DECLARE_FLAGS and Q_FLAGS
648 QFlags<EnumType> flags2(EnumValue2);
649 qDebug() << flags2;
650 QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::EnumType>(EnumValue2)"));
651
652 // A now for one that was fully declared
653 tst_QDebug::Flags flags3(EnumFlag1);
654 qDebug() << flags3;
655 QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::FlagType>(EnumFlag1)"));
656}
657
658void tst_QDebug::textStreamModifiers() const
659{
660 QString file, function;
661 int line = 0;
662 MessageHandlerSetter mhs(myMessageHandler);
663 { qDebug() << Qt::hex << short(0xf) << int(0xf) << unsigned(0xf) << long(0xf) << qint64(0xf) << quint64(0xf); }
664#ifndef QT_NO_MESSAGELOGCONTEXT
665 file = __FILE__; line = __LINE__ - 2; function = Q_FUNC_INFO;
666#endif
667 QCOMPARE(s_msgType, QtDebugMsg);
668 QCOMPARE(s_msg, QString::fromLatin1("f f f f f f"));
669 QCOMPARE(QString::fromLatin1(s_file), file);
670 QCOMPARE(s_line, line);
671 QCOMPARE(QString::fromLatin1(s_function), function);
672}
673
674void tst_QDebug::resetFormat() const
675{
676 QString file, function;
677 int line = 0;
678 MessageHandlerSetter mhs(myMessageHandler);
679 {
680 QDebug d = qDebug();
681 d.nospace().noquote() << Qt::hex << int(0xf);
682 d.resetFormat() << int(0xf) << QStringLiteral("foo");
683 }
684#ifndef QT_NO_MESSAGELOGCONTEXT
685 file = __FILE__; line = __LINE__ - 5; function = Q_FUNC_INFO;
686#endif
687 QCOMPARE(s_msgType, QtDebugMsg);
688 QCOMPARE(s_msg, QString::fromLatin1("f15 \"foo\""));
689 QCOMPARE(QString::fromLatin1(s_file), file);
690 QCOMPARE(s_line, line);
691 QCOMPARE(QString::fromLatin1(s_function), function);
692}
693
694void tst_QDebug::defaultMessagehandler() const
695{
696 MessageHandlerSetter mhs(0); // set 0, should set default handler
697 QtMessageHandler defaultMessageHandler1 = qInstallMessageHandler((QtMessageHandler)0); // set 0, should set and return default handler
698 QVERIFY(defaultMessageHandler1);
699 QtMessageHandler defaultMessageHandler2 = qInstallMessageHandler(myMessageHandler); // set myMessageHandler and return default handler
700 bool same = (*defaultMessageHandler1 == *defaultMessageHandler2);
701 QVERIFY(same);
702 QtMessageHandler messageHandler = qInstallMessageHandler((QtMessageHandler)0); // set 0, should set default and return myMessageHandler
703 same = (*messageHandler == *myMessageHandler);
704 QVERIFY(same);
705}
706
707QMutex s_mutex;
708QStringList s_messages;
709QSemaphore s_sema;
710
711static void threadSafeMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
712{
713 QMutexLocker lock(&s_mutex);
714 s_messages.append(t: msg);
715 Q_UNUSED(type);
716 Q_UNUSED(context);
717}
718
719static void doDebug() // called in each thread
720{
721 s_sema.acquire();
722 qDebug() << "doDebug";
723}
724
725void tst_QDebug::threadSafety() const
726{
727 MessageHandlerSetter mhs(threadSafeMessageHandler);
728 const int numThreads = 10;
729 QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
730 QFutureSynchronizer<void> sync;
731 for (int i = 0; i < numThreads; ++i) {
732 sync.addFuture(future: QtConcurrent::run(functionPointer: &doDebug));
733 }
734 s_sema.release(n: numThreads);
735 sync.waitForFinished();
736 QMutexLocker lock(&s_mutex);
737 QCOMPARE(s_messages.count(), numThreads);
738 for (int i = 0; i < numThreads; ++i) {
739 QCOMPARE(s_messages.at(i), QStringLiteral("doDebug"));
740 }
741}
742
743// Should compile: instentiation of unrelated operator<< should not cause cause compilation
744// error in QDebug operators (QTBUG-47375)
745class TestClassA {};
746class TestClassB {};
747
748template <typename T>
749TestClassA& operator<< (TestClassA& s, T&) { return s; };
750template<> TestClassA& operator<< <TestClassB>(TestClassA& s, TestClassB& l);
751
752QTEST_MAIN(tst_QDebug);
753#include "tst_qdebug.moc"
754

source code of qtbase/tests/auto/corelib/io/qdebug/tst_qdebug.cpp