summaryrefslogtreecommitdiffstats
path: root/src/testlib/qtestcase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/testlib/qtestcase.cpp')
-rw-r--r--src/testlib/qtestcase.cpp217
1 files changed, 193 insertions, 24 deletions
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 2851f83427..acac632410 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtTest module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -47,6 +47,9 @@
#include <QtCore/qprocess.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlibraryinfo.h>
+#include <QtCore/private/qtools_p.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qtemporarydir.h>
#include <QtTest/private/qtestlog_p.h>
#include <QtTest/private/qtesttable_p.h>
@@ -84,6 +87,8 @@
QT_BEGIN_NAMESPACE
+using QtMiscUtils::toHexUpper;
+
/*!
\namespace QTest
\inmodule QtTest
@@ -94,6 +99,11 @@ QT_BEGIN_NAMESPACE
See the \l{Qt Test Overview} for information about how to write unit tests.
*/
+/*!
+ \namespace QTest::Internal
+ \internal
+*/
+
/*! \macro QVERIFY(condition)
\relates QTest
@@ -899,14 +909,21 @@ QT_BEGIN_NAMESPACE
Returns a textual representation of \a value. This function is used by
\l QCOMPARE() to output verbose information in case of a test failure.
- You can add specializations of this function to your test to enable
+ You can add specializations or overloads of this function to your test to enable
verbose output.
+ \b {Note:} Starting with Qt 5.5, you should prefer to provide a toString() function
+ in the type's namespace instead of specializing this template.
+ If your code needs to continue to work with the QTestLib from Qt 5.4 or
+ earlier, you need to continue to use specialization.
+
\b {Note:} The caller of toString() must delete the returned data
using \c{delete[]}. Your implementation should return a string
- created with \c{new[]} or qstrdup().
+ created with \c{new[]} or qstrdup(). The easiest way to do so is to
+ create a QByteArray or QString and calling QTest::toString() on it
+ (see second example below).
- Example:
+ Example for specializing (Qt ≤ 5.4):
\snippet code/src_qtestlib_qtestcase.cpp 16
@@ -915,6 +932,10 @@ QT_BEGIN_NAMESPACE
MyPoint fails, \l QCOMPARE() will call this function to output the
contents of \c MyPoint to the test log.
+ Same example, but with overloading (Qt ≥ 5.5):
+
+ \snippet code/src_qtestlib_qtestcase.cpp toString-overload
+
\sa QCOMPARE()
*/
@@ -1027,6 +1048,38 @@ QT_BEGIN_NAMESPACE
Returns a textual representation of the given \a variant.
*/
+/*!
+ \fn char *QTest::toString(QSizePolicy::ControlType ct)
+ \overload
+ \since 5.5
+
+ Returns a textual representation of control type \a ct.
+*/
+
+/*!
+ \fn char *QTest::toString(QSizePolicy::ControlTypes cts)
+ \overload
+ \since 5.5
+
+ Returns a textual representation of control types \a cts.
+*/
+
+/*!
+ \fn char *QTest::toString(QSizePolicy::Policy p)
+ \overload
+ \since 5.5
+
+ Returns a textual representation of policy \a p.
+*/
+
+/*!
+ \fn char *QTest::toString(QSizePolicy sp)
+ \overload
+ \since 5.5
+
+ Returns a textual representation of size policy \a sp.
+*/
+
/*! \fn void QTest::qWait(int ms)
Waits for \a ms milliseconds. While waiting, events will be processed and
@@ -1549,6 +1602,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
printf ("\n"
" QmlTest options:\n"
" -import dir : Specify an import directory.\n"
+ " -plugins dir : Specify a directory where to search for plugins.\n"
" -input dir/file : Specify the root directory for test cases or a single test case file.\n"
" -qtquick1 : Run with QtQuick 1 rather than QtQuick 2.\n"
" -translation file : Specify the translation file.\n"
@@ -1737,6 +1791,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml)
if (qml) {
fprintf(stderr, "\nqmltest related options:\n"
" -import : Specify an import directory.\n"
+ " -plugins : Specify a directory where to search for plugins.\n"
" -input : Specify the root directory for test cases.\n"
" -qtquick1 : Run with QtQuick 1 rather than QtQuick 2.\n"
);
@@ -2060,12 +2115,6 @@ void *fetchData(QTestData *data, const char *tagName, int typeId)
return data->data(idx);
}
-static char toHex(ushort value)
-{
- static const char hexdigits[] = "0123456789ABCDEF";
- return hexdigits[value & 0xF];
-}
-
/*!
\fn char* QTest::toHexRepresentation(const char *ba, int length)
@@ -2115,9 +2164,9 @@ char *toHexRepresentation(const char *ba, int length)
while (true) {
const char at = ba[i];
- result[o] = toHex(at >> 4);
+ result[o] = toHexUpper(at >> 4);
++o;
- result[o] = toHex(at);
+ result[o] = toHexUpper(at);
++i;
++o;
@@ -2134,8 +2183,76 @@ char *toHexRepresentation(const char *ba, int length)
/*!
\internal
+ Returns the same QByteArray but with only the ASCII characters still shown;
+ everything else is replaced with \c {\OOO}.
+*/
+char *toPrettyCString(const char *p, int length)
+{
+ bool trimmed = false;
+ QScopedArrayPointer<char> buffer(new char[256]);
+ const char *end = p + length;
+ char *dst = buffer.data();
+
+ *dst++ = '"';
+ for ( ; p != end; ++p) {
+ if (dst - buffer.data() > 246) {
+ // plus the the quote, the three dots and NUL, it's 251, 252 or 255
+ trimmed = true;
+ break;
+ }
+
+ if (*p < 0x7f && *p >= 0x20 && *p != '\\' && *p != '"') {
+ *dst++ = *p;
+ continue;
+ }
+
+ // write as an escape sequence
+ // this means we may advance dst to buffer.data() + 247 or 250
+ *dst++ = '\\';
+ switch (*p) {
+ case 0x5c:
+ case 0x22:
+ *dst++ = uchar(*p);
+ break;
+ case 0x8:
+ *dst++ = 'b';
+ break;
+ case 0xc:
+ *dst++ = 'f';
+ break;
+ case 0xa:
+ *dst++ = 'n';
+ break;
+ case 0xd:
+ *dst++ = 'r';
+ break;
+ case 0x9:
+ *dst++ = 't';
+ break;
+ default:
+ // write as octal
+ *dst++ = '0' + ((uchar(*p) >> 6) & 7);
+ *dst++ = '0' + ((uchar(*p) >> 3) & 7);
+ *dst++ = '0' + ((uchar(*p)) & 7);
+ }
+ }
+
+ *dst++ = '"';
+ if (trimmed) {
+ *dst++ = '.';
+ *dst++ = '.';
+ *dst++ = '.';
+ }
+ *dst++ = '\0';
+ return buffer.take();
+}
+
+/*!
+ \internal
Returns the same QString but with only the ASCII characters still shown;
everything else is replaced with \c {\uXXXX}.
+
+ Similar to QDebug::putString().
*/
char *toPrettyUnicode(const ushort *p, int length)
{
@@ -2183,10 +2300,10 @@ char *toPrettyUnicode(const ushort *p, int length)
break;
default:
*dst++ = 'u';
- *dst++ = toHex(*p >> 12);
- *dst++ = toHex(*p >> 8);
- *dst++ = toHex(*p >> 4);
- *dst++ = toHex(*p);
+ *dst++ = toHexUpper(*p >> 12);
+ *dst++ = toHexUpper(*p >> 8);
+ *dst++ = toHexUpper(*p >> 4);
+ *dst++ = toHexUpper(*p);
}
}
@@ -2587,7 +2704,7 @@ void QTest::qWarn(const char *message, const char *file, int line)
}
/*!
- Ignores messages created by qDebug() or qWarning(). If the \a message
+ Ignores messages created by qDebug(), qInfo() or qWarning(). If the \a message
with the corresponding \a type is outputted, it will be removed from the
test log. If the test finished and the \a message was not outputted,
a test failure is appended to the test log.
@@ -2611,7 +2728,7 @@ void QTest::ignoreMessage(QtMsgType type, const char *message)
/*!
\overload
- Ignores messages created by qDebug() or qWarning(). If the message
+ Ignores messages created by qDebug(), qInfo() or qWarning(). If the message
matching \a messagePattern
with the corresponding \a type is outputted, it will be removed from the
test log. If the test finished and the message was not outputted,
@@ -2640,6 +2757,58 @@ static inline bool isWindowsBuildDirectory(const QString &dirName)
}
#endif
+/* !
+ Extract a directory from resources to disk. The content is extracted
+ recursively to a temporary folder. The extracted content is not removed
+ automatically.
+
+ \a dirName is the name of the directory to extract from resources.
+
+ Returns the path where the data was extracted or an empty string in case of
+ errors.
+ */
+QString QTest::qExtractTestData(const QString &dirName)
+{
+ QTemporaryDir temporaryDir;
+ temporaryDir.setAutoRemove(false);
+
+ if (!temporaryDir.isValid())
+ return QString();
+
+ const QString dataPath = temporaryDir.path();
+ const QString resourcePath = QLatin1Char(':') + dirName;
+ const QFileInfo fileInfo(resourcePath);
+
+ if (!fileInfo.isDir()) {
+ qWarning("Resource path '%s' is not a directory.", qPrintable(resourcePath));
+ return QString();
+ }
+
+ QDirIterator it(resourcePath, QDirIterator::Subdirectories);
+ if (!it.hasNext()) {
+ qWarning("Resource directory '%s' is empty.", qPrintable(resourcePath));
+ return QString();
+ }
+
+ while (it.hasNext()) {
+ it.next();
+
+ QFileInfo fileInfo = it.fileInfo();
+
+ if (!fileInfo.isDir()) {
+ const QString destination = dataPath + QLatin1Char('/') + fileInfo.filePath().mid(resourcePath.length());
+ QFileInfo destinationFileInfo(destination);
+ QDir().mkpath(destinationFileInfo.path());
+ if (!QFile::copy(fileInfo.filePath(), destination)) {
+ qWarning("Failed to copy '%s'.", qPrintable(fileInfo.filePath()));
+ return QString();
+ }
+ }
+ }
+
+ return dataPath;
+}
+
/*! \internal
*/