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 QtTest module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtTest/private/qabstracttestlogger_p.h>
41#include <QtTest/qtestassert.h>
42#include <qtestresult_p.h>
43
44#include <QtCore/qbytearray.h>
45#include <QtCore/qstring.h>
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <stdarg.h>
50
51#ifndef Q_OS_WIN
52#include <unistd.h>
53#endif
54
55#ifdef Q_OS_ANDROID
56#include <sys/stat.h>
57#endif
58
59QT_BEGIN_NAMESPACE
60
61QAbstractTestLogger::QAbstractTestLogger(const char *filename)
62{
63 if (!filename) {
64 stream = stdout;
65 return;
66 }
67#if defined(_MSC_VER)
68 if (::fopen_s(&stream, filename, "wt")) {
69#else
70 stream = ::fopen(filename, "wt");
71 if (!stream) {
72#endif
73 fprintf(stderr, "Unable to open file for logging: %s\n", filename);
74 ::exit(1);
75 }
76#ifdef Q_OS_ANDROID
77 else {
78 // Make sure output is world-readable on Android
79 ::chmod(filename, 0666);
80 }
81#endif
82}
83
84QAbstractTestLogger::~QAbstractTestLogger()
85{
86 QTEST_ASSERT(stream);
87 if (stream != stdout) {
88 fclose(stream);
89 }
90 stream = nullptr;
91}
92
93void QAbstractTestLogger::filterUnprintable(char *str) const
94{
95 unsigned char *idx = reinterpret_cast<unsigned char *>(str);
96 while (*idx) {
97 if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx == 0x7f))
98 *idx = '?';
99 ++idx;
100 }
101}
102
103void QAbstractTestLogger::outputString(const char *msg)
104{
105 QTEST_ASSERT(stream);
106 QTEST_ASSERT(msg);
107
108 char *filtered = new char[strlen(msg) + 1];
109 strcpy(filtered, msg);
110 filterUnprintable(filtered);
111
112 ::fputs(filtered, stream);
113 ::fflush(stream);
114
115 delete [] filtered;
116}
117
118void QAbstractTestLogger::startLogging()
119{
120}
121
122void QAbstractTestLogger::stopLogging()
123{
124}
125
126void QAbstractTestLogger::addMessage(QtMsgType type, const QMessageLogContext &context,
127 const QString &message)
128{
129 QAbstractTestLogger::MessageTypes messageType = [=]() {
130 switch (type) {
131 case QtDebugMsg: return QAbstractTestLogger::QDebug;
132 case QtInfoMsg: return QAbstractTestLogger::QInfo;
133 case QtCriticalMsg: return QAbstractTestLogger::QSystem;
134 case QtWarningMsg: return QAbstractTestLogger::QWarning;
135 case QtFatalMsg: return QAbstractTestLogger::QFatal;
136 }
137 Q_UNREACHABLE();
138 return QAbstractTestLogger::QFatal;
139 }();
140
141 QString formattedMessage = qFormatLogMessage(type, context, message);
142
143 // Note that we explicitly ignore the file and line of the context here,
144 // as that's what QTest::messageHandler used to do when calling the same
145 // overload directly.
146 addMessage(messageType, formattedMessage);
147}
148
149namespace QTest
150{
151
152extern void filter_unprintable(char *str);
153
154/*!
155 \fn int QTest::qt_asprintf(QTestCharBuffer *buf, const char *format, ...);
156 \internal
157 */
158int qt_asprintf(QTestCharBuffer *str, const char *format, ...)
159{
160 static const int MAXSIZE = 1024*1024*2;
161
162 Q_ASSERT(str);
163
164 int size = str->size();
165
166 va_list ap;
167 int res = 0;
168
169 for (;;) {
170 va_start(ap, format);
171 res = qvsnprintf(str->data(), size, format, ap);
172 va_end(ap);
173 str->data()[size - 1] = '\0';
174 if (res >= 0 && res < size) {
175 // We succeeded
176 break;
177 }
178 // buffer wasn't big enough, try again.
179 // Note, we're assuming that a result of -1 is always due to running out of space.
180 size *= 2;
181 if (size > MAXSIZE) {
182 break;
183 }
184 if (!str->reset(size))
185 break; // out of memory - take what we have
186 }
187
188 return res;
189}
190
191}
192
193namespace QTestPrivate
194{
195
196void generateTestIdentifier(QTestCharBuffer *identifier, int parts)
197{
198 const char *testObject = parts & TestObject ? QTestResult::currentTestObjectName() : "";
199 const char *testFunction = parts & TestFunction ? (QTestResult::currentTestFunction() ? QTestResult::currentTestFunction() : "UnknownTestFunc") : "";
200 const char *objectFunctionFiller = parts & TestObject && parts & (TestFunction | TestDataTag) ? "::" : "";
201 const char *testFuctionStart = parts & TestFunction ? "(" : "";
202 const char *testFuctionEnd = parts & TestFunction ? ")" : "";
203
204 const char *dataTag = (parts & TestDataTag) && QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
205 const char *globalDataTag = (parts & TestDataTag) && QTestResult::currentGlobalDataTag() ? QTestResult::currentGlobalDataTag() : "";
206 const char *tagFiller = (dataTag[0] && globalDataTag[0]) ? ":" : "";
207
208 QTest::qt_asprintf(identifier, "%s%s%s%s%s%s%s%s",
209 testObject, objectFunctionFiller, testFunction, testFuctionStart,
210 globalDataTag, tagFiller, dataTag, testFuctionEnd);
211}
212
213}
214
215QT_END_NAMESPACE
216