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
93bool QAbstractTestLogger::isLoggingToStdout() const
94{
95 return stream == stdout;
96}
97
98void QAbstractTestLogger::filterUnprintable(char *str) const
99{
100 unsigned char *idx = reinterpret_cast<unsigned char *>(str);
101 while (*idx) {
102 if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx == 0x7f))
103 *idx = '?';
104 ++idx;
105 }
106}
107
108void QAbstractTestLogger::outputString(const char *msg)
109{
110 QTEST_ASSERT(stream);
111 QTEST_ASSERT(msg);
112
113 char *filtered = new char[strlen(msg) + 1];
114 strcpy(filtered, msg);
115 filterUnprintable(filtered);
116
117 ::fputs(filtered, stream);
118 ::fflush(stream);
119
120 delete [] filtered;
121}
122
123void QAbstractTestLogger::startLogging()
124{
125}
126
127void QAbstractTestLogger::stopLogging()
128{
129}
130
131void QAbstractTestLogger::addMessage(QtMsgType type, const QMessageLogContext &context,
132 const QString &message)
133{
134 QAbstractTestLogger::MessageTypes messageType = [=]() {
135 switch (type) {
136 case QtDebugMsg: return QAbstractTestLogger::QDebug;
137 case QtInfoMsg: return QAbstractTestLogger::QInfo;
138 case QtCriticalMsg: return QAbstractTestLogger::QSystem;
139 case QtWarningMsg: return QAbstractTestLogger::QWarning;
140 case QtFatalMsg: return QAbstractTestLogger::QFatal;
141 }
142 Q_UNREACHABLE();
143 return QAbstractTestLogger::QFatal;
144 }();
145
146 QString formattedMessage = qFormatLogMessage(type, context, message);
147
148 // Note that we explicitly ignore the file and line of the context here,
149 // as that's what QTest::messageHandler used to do when calling the same
150 // overload directly.
151 addMessage(messageType, formattedMessage);
152}
153
154namespace QTest
155{
156
157extern void filter_unprintable(char *str);
158
159/*!
160 \fn int QTest::qt_asprintf(QTestCharBuffer *buf, const char *format, ...);
161 \internal
162 */
163int qt_asprintf(QTestCharBuffer *str, const char *format, ...)
164{
165 static const int MAXSIZE = 1024*1024*2;
166
167 Q_ASSERT(str);
168
169 int size = str->size();
170
171 va_list ap;
172 int res = 0;
173
174 for (;;) {
175 va_start(ap, format);
176 res = qvsnprintf(str->data(), size, format, ap);
177 va_end(ap);
178 str->data()[size - 1] = '\0';
179 if (res >= 0 && res < size) {
180 // We succeeded
181 break;
182 }
183 // buffer wasn't big enough, try again.
184 // Note, we're assuming that a result of -1 is always due to running out of space.
185 size *= 2;
186 if (size > MAXSIZE) {
187 break;
188 }
189 if (!str->reset(size))
190 break; // out of memory - take what we have
191 }
192
193 return res;
194}
195
196}
197
198namespace QTestPrivate
199{
200
201void generateTestIdentifier(QTestCharBuffer *identifier, int parts)
202{
203 const char *testObject = parts & TestObject ? QTestResult::currentTestObjectName() : "";
204 const char *testFunction = parts & TestFunction ? (QTestResult::currentTestFunction() ? QTestResult::currentTestFunction() : "UnknownTestFunc") : "";
205 const char *objectFunctionFiller = parts & TestObject && parts & (TestFunction | TestDataTag) ? "::" : "";
206 const char *testFuctionStart = parts & TestFunction ? "(" : "";
207 const char *testFuctionEnd = parts & TestFunction ? ")" : "";
208
209 const char *dataTag = (parts & TestDataTag) && QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
210 const char *globalDataTag = (parts & TestDataTag) && QTestResult::currentGlobalDataTag() ? QTestResult::currentGlobalDataTag() : "";
211 const char *tagFiller = (dataTag[0] && globalDataTag[0]) ? ":" : "";
212
213 QTest::qt_asprintf(identifier, "%s%s%s%s%s%s%s%s",
214 testObject, objectFunctionFiller, testFunction, testFuctionStart,
215 globalDataTag, tagFiller, dataTag, testFuctionEnd);
216}
217
218}
219
220QT_END_NAMESPACE
221