Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qabstracttestlogger.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtTest/private/qabstracttestlogger_p.h>
5#include <QtTest/qtestassert.h>
6#include <qbenchmark_p.h>
7#include <qtestresult_p.h>
8
9#include <QtCore/qbytearray.h>
10#include <QtCore/qstring.h>
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <stdarg.h>
15
16#ifndef Q_OS_WIN
17#include <unistd.h>
18#endif
19
20#ifdef Q_OS_ANDROID
21#include <sys/stat.h>
22#endif
23
114{
115 if (!filename) {
116 stream = stdout;
117 return;
118 }
119#if defined(_MSC_VER)
120 if (::fopen_s(&stream, filename, "wt")) {
121#else
122 stream = ::fopen(filename, "wt");
123 if (!stream) {
124#endif
125 fprintf(stderr, "Unable to open file for logging: %s\n", filename);
126 ::exit(1);
127 }
128#ifdef Q_OS_ANDROID
129 else {
130 // Make sure output is world-readable on Android
131 ::chmod(filename, 0666);
132 }
133#endif
134}
135
143{
145 if (stream != stdout)
146 fclose(stream);
147 stream = nullptr;
148}
149
159{
160 return false;
161}
162
167{
168 return stream == stdout;
169}
170
178{
179 unsigned char *idx = reinterpret_cast<unsigned char *>(str);
180 while (*idx) {
181 if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx == 0x7f))
182 *idx = '?';
183 ++idx;
184 }
185}
186
195{
197 QTEST_ASSERT(msg);
198
199 char *filtered = new char[strlen(msg) + 1];
200 strcpy(filtered, msg);
201 filterUnprintable(filtered);
202
203 ::fputs(filtered, stream);
204 ::fflush(stream);
205
206 delete [] filtered;
207}
208
223
238
239void QAbstractTestLogger::addBenchmarkResults(const QList<QBenchmarkResult> &result)
240{
241 for (const auto &m : result)
243}
244
364 const QString &message)
365{
366 QAbstractTestLogger::MessageTypes messageType = [=]() {
367 switch (type) {
373 }
374 Q_UNREACHABLE_RETURN(QAbstractTestLogger::QFatal);
375 }();
376
377 QString formattedMessage = qFormatLogMessage(type, context, message);
378
379 // Note that we explicitly ignore the file and line of the context here,
380 // as that's what QTest::messageHandler used to do when calling the same
381 // overload directly.
382 addMessage(messageType, formattedMessage);
383}
384
385namespace
386{
387 constexpr int MAXSIZE = 1024 * 1024 * 2;
388}
389
390namespace QTest
391{
392
397int qt_asprintf(QTestCharBuffer *str, const char *format, ...)
398{
399 Q_ASSERT(str);
400 int size = str->size();
401 Q_ASSERT(size > 0);
402
403 va_list ap;
404 int res = 0;
405
406 do {
407 va_start(ap, format);
408 res = qvsnprintf(str->data(), size, format, ap);
409 va_end(ap);
410 // vsnprintf() reliably '\0'-terminates
411 Q_ASSERT(res < 0 || str->data()[res < size ? res : size - 1] == '\0');
412 // Note, we're assuming that a result of -1 is always due to running out of space.
413 if (res >= 0 && res < size) // Success
414 break;
415
416 // Buffer wasn't big enough, try again:
417 size *= 2;
418 // If too large or out of memory, take what we have:
419 } while (size <= MAXSIZE && str->reset(size));
420
421 return res;
422}
423
424}
425
426namespace QTestPrivate
427{
428
429void generateTestIdentifier(QTestCharBuffer *identifier, int parts)
430{
431 const char *testObject = parts & TestObject ? QTestResult::currentTestObjectName() : "";
432 const char *testFunction = parts & TestFunction ? (QTestResult::currentTestFunction() ? QTestResult::currentTestFunction() : "UnknownTestFunc") : "";
433 const char *objectFunctionFiller = parts & TestObject && parts & (TestFunction | TestDataTag) ? "::" : "";
434 const char *testFuctionStart = parts & TestFunction ? "(" : "";
435 const char *testFuctionEnd = parts & TestFunction ? ")" : "";
436
437 const char *dataTag = (parts & TestDataTag) && QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
438 const char *globalDataTag = (parts & TestDataTag) && QTestResult::currentGlobalDataTag() ? QTestResult::currentGlobalDataTag() : "";
439 const char *tagFiller = (dataTag[0] && globalDataTag[0]) ? ":" : "";
440
441 QTest::qt_asprintf(identifier, "%s%s%s%s%s%s%s%s",
442 testObject, objectFunctionFiller, testFunction, testFuctionStart,
443 globalDataTag, tagFiller, dataTag, testFuctionEnd);
444}
445
446// strcat() for QTestCharBuffer objects:
447bool appendCharBuffer(QTestCharBuffer *accumulator, const QTestCharBuffer &more)
448{
449 const auto bufsize = [](const QTestCharBuffer &buf) -> int {
450 const int max = buf.size();
451 return max > 0 ? int(qstrnlen(buf.constData(), max)) : 0;
452 };
453 const int extra = bufsize(more);
454 if (extra <= 0)
455 return true; // Nothing to do, fatuous success
456
457 const int oldsize = bufsize(*accumulator);
458 const int newsize = oldsize + extra + 1; // 1 for final '\0'
459 if (newsize > MAXSIZE || !accumulator->resize(newsize))
460 return false; // too big or unable to grow
461
462 char *tail = accumulator->data() + oldsize;
463 memcpy(tail, more.constData(), extra);
464 tail[extra] = '\0';
465 return true;
466}
467
468}
469
void outputString(const char *msg)
Convenience method to write msg to the output stream.
virtual ~QAbstractTestLogger()
Destroys the logger object.
virtual void addBenchmarkResult(const QBenchmarkResult &result)=0
This virtual method is called after a benchmark has been run enough times to produce usable data.
bool isLoggingToStdout() const
Returns true if the output stream is standard output.
QAbstractTestLogger(const char *filename)
Constructs the base-class parts of the logger.
virtual void startLogging()
Called before the start of a test run.
virtual void addMessage(QtMsgType, const QMessageLogContext &, const QString &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
MessageTypes
The members whose names begin with Q describe messages that originate in calls, by the test or code u...
virtual bool isRepeatSupported() const
Returns true if the logger supports repeated test runs.
void filterUnprintable(char *str) const
Helper utility to blot out unprintable characters in str.
virtual void addBenchmarkResults(const QList< QBenchmarkResult > &result)
virtual void stopLogging()
Called after the end of a test run.
\inmodule QtCore
Definition qlogging.h:42
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
static const char * currentTestObjectName()
static const char * currentGlobalDataTag()
static const char * currentDataTag()
static const char * currentTestFunction()
QString str
[2]
Combined button and popup list for selecting options.
void generateTestIdentifier(QTestCharBuffer *identifier, int parts)
bool appendCharBuffer(QTestCharBuffer *accumulator, const QTestCharBuffer &more)
int qt_asprintf(QTestCharBuffer *str, const char *format,...)
static void * context
Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap)
size_t qstrnlen(const char *str, size_t maxlen)
EGLStreamKHR stream
Q_CORE_EXPORT QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &buf)
QtMsgType
Definition qlogging.h:29
@ QtCriticalMsg
Definition qlogging.h:32
@ QtInfoMsg
Definition qlogging.h:34
@ QtWarningMsg
Definition qlogging.h:31
@ QtFatalMsg
Definition qlogging.h:33
@ QtDebugMsg
Definition qlogging.h:30
const GLfloat * m
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLsizei bufsize
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum format
GLboolean reset
GLuint res
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QTEST_ASSERT(cond)
Definition qtestassert.h:11
void testObject()
[11]
bool resize(int newSize)