summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib')
-rw-r--r--tests/auto/corelib/global/qlogging/tst_qlogging.cpp10
-rw-r--r--tests/auto/corelib/io/io.pro2
-rw-r--r--tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp3
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp1
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom1/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom1/test30
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom2/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom3/+custom2/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom3/+custom4/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom3/+custom5/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom3/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/+custom5/+custom3/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/extras/test20
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+android/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+blackberry/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+generic_unix/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+ios/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+linux/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+osx/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+wince/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+windows/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/qfileselector.pro6
-rw-r--r--tests/auto/corelib/io/qfileselector/qfileselector.qrc23
-rw-r--r--tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp199
-rw-r--r--tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro2
-rw-r--r--tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp4
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp22
-rw-r--r--tests/auto/corelib/io/qloggingcategory/qloggingcategory.pro7
-rw-r--r--tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp818
-rw-r--r--tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp9
-rw-r--r--tests/auto/corelib/io/qprocess/testForwarding/main.cpp45
-rw-r--r--tests/auto/corelib/io/qprocess/tst_qprocess.cpp90
-rw-r--r--tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp5
-rw-r--r--tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp40
-rw-r--r--tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp8
-rw-r--r--tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp11
-rw-r--r--tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp3
-rw-r--r--tests/auto/corelib/io/qurl/qurl.pro2
-rw-r--r--tests/auto/corelib/io/qurl/tst_qurl.cpp475
-rw-r--r--tests/auto/corelib/io/qurl/tst_qurl_mac.mm63
-rw-r--r--tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp23
-rw-r--r--tests/auto/corelib/json/tst_qtjson.cpp108
-rw-r--r--tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp51
-rw-r--r--tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp30
-rw-r--r--tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp24
-rw-r--r--tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp4
-rw-r--r--tests/auto/corelib/kernel/qmetatype/qmetatype.pro1
-rw-r--r--tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp450
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp266
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp538
-rw-r--r--tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp10
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp49
-rwxr-xr-xtests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl209
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro56
-rwxr-xr-xtests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl112
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro1
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/tst/tst.pro5
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp78
-rw-r--r--tests/auto/corelib/thread/qthread/tst_qthread.cpp40
-rw-r--r--tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp121
-rw-r--r--tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp87
-rw-r--r--tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp35
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro3
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp101
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro6
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp559
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro4
-rw-r--r--tests/auto/corelib/tools/qdate/tst_qdate.cpp56
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp1126
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp14
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp30
-rw-r--r--tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro5
-rw-r--r--tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp1100
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp49
-rw-r--r--tests/auto/corelib/tools/qlocale/tst_qlocale.cpp100
-rw-r--r--tests/auto/corelib/tools/qmap/tst_qmap.cpp86
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/externaltests.cpp10
-rw-r--r--tests/auto/corelib/tools/qstring/qstring.pro5
-rw-r--r--tests/auto/corelib/tools/qstring/tst_qstring.cpp11
-rw-r--r--tests/auto/corelib/tools/qstring/tst_qstring_mac.mm79
-rw-r--r--tests/auto/corelib/tools/qstringref/tst_qstringref.cpp142
-rw-r--r--tests/auto/corelib/tools/qtime/tst_qtime.cpp134
-rw-r--r--tests/auto/corelib/tools/tools.pro2
85 files changed, 7297 insertions, 471 deletions
diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
index 04ce504189..94387704f6 100644
--- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
+++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
@@ -101,6 +101,7 @@ void tst_qmessagehandler::initTestCase()
QVERIFY2(!m_appDir.isEmpty(), qPrintable(
QString::fromLatin1("Couldn't find helper app dir starting from %1.").arg(QDir::currentPath())));
+#ifndef QT_NO_PROCESS
m_baseEnvironment = QProcess::systemEnvironment();
for (int i = 0; i < m_baseEnvironment.count(); ++i) {
if (m_baseEnvironment.at(i).startsWith("QT_MESSAGE_PATTERN=")) {
@@ -108,6 +109,7 @@ void tst_qmessagehandler::initTestCase()
break;
}
}
+#endif // !QT_NO_PROCESS
}
void tst_qmessagehandler::cleanup()
@@ -641,6 +643,9 @@ void tst_qmessagehandler::cleanupFuncinfo()
void tst_qmessagehandler::qMessagePattern()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
QProcess process;
const QString appExe = m_appDir + "/app";
@@ -710,10 +715,14 @@ void tst_qmessagehandler::qMessagePattern()
output.replace("\r\n", "\n");
#endif
QCOMPARE(QString::fromLatin1(output), QString::fromLatin1(expected));
+#endif // !QT_NO_PROCESS
}
void tst_qmessagehandler::qMessagePatternIf()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
QProcess process;
const QString appExe = m_appDir + "/app";
@@ -773,6 +782,7 @@ void tst_qmessagehandler::qMessagePatternIf()
QVERIFY(output.contains("QT_MESSAGE_PATTERN: %{if-*} cannot be nested"));
QVERIFY(output.contains("A DEBUG qDebug"));
QVERIFY(output.contains("A qWarning"));
+#endif // !QT_NO_PROCESS
}
QTEST_MAIN(tst_qmessagehandler)
diff --git a/tests/auto/corelib/io/io.pro b/tests/auto/corelib/io/io.pro
index b3a51c6f6e..41d7e7e08b 100644
--- a/tests/auto/corelib/io/io.pro
+++ b/tests/auto/corelib/io/io.pro
@@ -10,11 +10,13 @@ SUBDIRS=\
qfile \
largefile \
qfileinfo \
+ qfileselector \
qfilesystementry \
qfilesystemwatcher \
qiodevice \
qipaddress \
qlockfile \
+ qloggingcategory \
qnodebug \
qprocess \
qprocess-noapplication \
diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
index 3607467ff9..a6d76ea7b6 100644
--- a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
@@ -269,7 +269,8 @@ static int NColorRoles[] = {
QPalette::ToolTipText + 1, // Qt_4_6
QPalette::ToolTipText + 1, // Qt_5_0
QPalette::ToolTipText + 1, // Qt_5_1
- 0 // add the correct value for Qt_5_2 here later
+ QPalette::ToolTipText + 1, // Qt_5_2
+ 0 // add the correct value for Qt_5_3 here later
};
// Testing get/set functions
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index af2578ac37..d2171cc64a 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -438,6 +438,7 @@ void tst_QFileInfo::exists()
QFileInfo fi(path);
QCOMPARE(fi.exists(), expected);
+ QCOMPARE(QFileInfo::exists(path), expected);
}
void tst_QFileInfo::absolutePath_data()
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom1/test b/tests/auto/corelib/io/qfileselector/extras/+custom1/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom1/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom1/test3 b/tests/auto/corelib/io/qfileselector/extras/+custom1/test3
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom1/test3
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom2/test b/tests/auto/corelib/io/qfileselector/extras/+custom2/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom2/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom2/test b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom2/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom2/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom4/test b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom4/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom4/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom5/test b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom5/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom3/+custom5/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom3/test b/tests/auto/corelib/io/qfileselector/extras/+custom3/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom3/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/+custom5/+custom3/test b/tests/auto/corelib/io/qfileselector/extras/+custom5/+custom3/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/+custom5/+custom3/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/test b/tests/auto/corelib/io/qfileselector/extras/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/test
diff --git a/tests/auto/corelib/io/qfileselector/extras/test2 b/tests/auto/corelib/io/qfileselector/extras/test2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/extras/test2
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+android/test b/tests/auto/corelib/io/qfileselector/platforms/+android/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+android/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+blackberry/test b/tests/auto/corelib/io/qfileselector/platforms/+blackberry/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+blackberry/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+generic_unix/test b/tests/auto/corelib/io/qfileselector/platforms/+generic_unix/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+generic_unix/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+ios/test b/tests/auto/corelib/io/qfileselector/platforms/+ios/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+ios/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+linux/test b/tests/auto/corelib/io/qfileselector/platforms/+linux/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+linux/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+osx/test b/tests/auto/corelib/io/qfileselector/platforms/+osx/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+osx/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+wince/test b/tests/auto/corelib/io/qfileselector/platforms/+wince/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+wince/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+windows/test b/tests/auto/corelib/io/qfileselector/platforms/+windows/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+windows/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/test b/tests/auto/corelib/io/qfileselector/platforms/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/test
diff --git a/tests/auto/corelib/io/qfileselector/qfileselector.pro b/tests/auto/corelib/io/qfileselector/qfileselector.pro
new file mode 100644
index 0000000000..ded3d6502e
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/qfileselector.pro
@@ -0,0 +1,6 @@
+CONFIG += parallel_test
+CONFIG += testcase
+TARGET = tst_qfileselectors
+QT = core-private testlib
+SOURCES = tst_qfileselector.cpp
+RESOURCES = qfileselector.qrc
diff --git a/tests/auto/corelib/io/qfileselector/qfileselector.qrc b/tests/auto/corelib/io/qfileselector/qfileselector.qrc
new file mode 100644
index 0000000000..c644e41107
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/qfileselector.qrc
@@ -0,0 +1,23 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+ <file>extras/test</file>
+ <file>extras/test2</file>
+ <file>extras/+custom1/test</file>
+ <file>extras/+custom1/test3</file>
+ <file>extras/+custom2/test</file>
+ <file>extras/+custom3/test</file>
+ <file>extras/+custom3/+custom2/test</file>
+ <file>extras/+custom3/+custom4/test</file>
+ <file>extras/+custom3/+custom5/test</file>
+ <file>extras/+custom5/+custom3/test</file>
+ <file>platforms/test</file>
+ <file>platforms/+android/test</file>
+ <file>platforms/+blackberry/test</file>
+ <file>platforms/+ios/test</file>
+ <file>platforms/+osx/test</file>
+ <file>platforms/+wince/test</file>
+ <file>platforms/+windows/test</file>
+ <file>platforms/+linux/test</file>
+ <file>platforms/+generic_unix/test</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp
new file mode 100644
index 0000000000..2baebd0296
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <qplatformdefs.h>
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QString>
+
+#include <private/qfileselector_p.h>
+#include <private/qabstractfileengine_p.h>
+#include <private/qfsfileengine_p.h>
+#include <private/qfilesystemengine_p.h>
+
+const ushort selectorIndicator = '+';
+
+class tst_QFileSelector : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QFileSelector() {}
+
+private slots:
+ void basicTest_data();
+ void basicTest();
+
+ void urlConvenience_data();
+ void urlConvenience();
+};
+
+void tst_QFileSelector::basicTest_data()
+{
+ /* Files existing for this test
+ * platform/test
+ * platform/+<platform>/test for all <platform> in QFileSelectorPrivate::platformSelectors()
+ * extras/test
+ * extras/test2 to test for when selector directories exist, but don't have the files
+ * extras/+custom1/test
+ * extras/+custom1/test3 to test for when base file doesn't exist
+ * extras/+custom2/test
+ * extras/+custom3/test
+ * extras/+custom3/+custom2/test
+ * extras/+custom3/+custom4/test
+ * extras/+custom3/+custom5/test
+ * extras/+custom5/+custom3/test
+ */
+ QTest::addColumn<QString>("testPath");
+ QTest::addColumn<QStringList>("customSelectors");
+ QTest::addColumn<QString>("expectedPath");
+
+ QString test("/test");// '/' is here so dir string can also be selector string
+ QTest::newRow("platform") << QString(":/platforms/test") << QStringList()
+ << QString(":/platforms/") + QLatin1Char(selectorIndicator)
+ + QFileSelectorPrivate::platformSelectors().first() + test;
+
+ QString resourceTestPath(":/extras/test");
+ QString custom1("custom1");
+ QTest::newRow("custom1-noselector") << resourceTestPath << QStringList()
+ << QString(":/extras") + test;
+
+ QTest::newRow("custom1-withselector") << resourceTestPath << (QStringList() << custom1)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom1 + test;
+
+ QTest::newRow("customX-withselector-nofile") << QString(":/extras/test2") << (QStringList() << custom1)
+ << QString(":/extras/test2");
+
+ QTest::newRow("custom1-withselector-nobasefile") << QString(":/extras/test3") << (QStringList() << custom1)
+ << QString(":/extras/test3");
+
+ QString custom2("custom2");
+ QString custom3("custom3");
+ QString custom4("custom4");
+ QString custom5("custom5");
+ QString slash("/");
+ QTest::newRow("custom12") << resourceTestPath << (QStringList() << custom1 << custom2)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom1 + test;
+
+ QTest::newRow("custom21") << resourceTestPath << (QStringList() << custom2 << custom1)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom2 + test;
+
+ QTest::newRow("custom213") << resourceTestPath << (QStringList() << custom2 << custom1 << custom3)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom2 + test;
+
+ QTest::newRow("custom23") << resourceTestPath << (QStringList() << custom2 << custom3)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom2 + test;
+
+ QTest::newRow("custom34nested") << resourceTestPath << (QStringList() << custom3 << custom4)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom3 + slash
+ + QLatin1Char(selectorIndicator) + custom4 + test;
+
+ QTest::newRow("custom43nested") << resourceTestPath << (QStringList() << custom4 << custom3)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom3 + slash
+ + QLatin1Char(selectorIndicator) + custom4 + test;
+
+ QTest::newRow("custom35conflict") << resourceTestPath << (QStringList() << custom3 << custom5)
+ << QString(":/extras/") + QLatin1Char(selectorIndicator) + custom3 + slash
+ + QLatin1Char(selectorIndicator) + custom5 + test;
+
+ QTest::newRow("relativePaths") << QFINDTESTDATA("extras/test") << (QStringList() << custom1)
+ << QFINDTESTDATA(QString("extras/") + QLatin1Char(selectorIndicator) + custom1
+ + QString("/test"));
+}
+
+void tst_QFileSelector::basicTest()
+{
+ QFETCH(QString, testPath);
+ QFETCH(QStringList, customSelectors);
+ QFETCH(QString, expectedPath);
+
+ QFileSelector fs;
+ fs.setExtraSelectors(customSelectors);
+ QCOMPARE(fs.select(testPath), expectedPath);
+}
+
+void tst_QFileSelector::urlConvenience_data()
+{
+ /* Files existing for this test
+ * extras/test
+ * extras/+custom1/test
+ */
+ QTest::addColumn<QUrl>("testUrl");
+ QTest::addColumn<QStringList>("customSelectors");
+ QTest::addColumn<QUrl>("expectedUrl");
+
+ QString test("/test");// '/' is here so dir string can also be selector string
+ QString custom1("custom1");
+
+ QTest::newRow("qrc") << QUrl("qrc:///extras/test") << (QStringList() << custom1)
+ << QUrl(QString("qrc:///extras/") + QLatin1Char(selectorIndicator) + custom1 + test);
+
+ QString fileBasePath = QFINDTESTDATA("extras/test");
+ QString fileSelectedPath = QFINDTESTDATA(QString("extras/") + QLatin1Char(selectorIndicator)
+ + custom1 + QString("/test"));
+ QTest::newRow("file") << QUrl::fromLocalFile(fileBasePath) << (QStringList() << custom1)
+ << QUrl::fromLocalFile(fileSelectedPath);
+
+ // http://qt-project.org/images/qtdn/sprites-combined-latest.png is chosen as a representative real world URL
+ // But note that this test is checking that http urls are NOT selected so it shouldn't be checked
+ QUrl testHttpUrl("http://qt-project.org/images/sprites-combined-latest.png");
+ QTest::newRow("http") << testHttpUrl << (QStringList() << QString("qtdn")) << testHttpUrl;
+}
+
+void tst_QFileSelector::urlConvenience()
+{
+ QFETCH(QUrl, testUrl);
+ QFETCH(QStringList, customSelectors);
+ QFETCH(QUrl, expectedUrl);
+
+ QFileSelector fs;
+ //All rows of this test use only custom selectors, so should not select before the setExtra call
+ QCOMPARE(fs.select(testUrl), testUrl);
+ fs.setExtraSelectors(customSelectors);
+ QCOMPARE(fs.select(testUrl), expectedUrl);
+}
+
+QTEST_MAIN(tst_QFileSelector)
+#include "tst_qfileselector.moc"
diff --git a/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro
index 1faa089c6e..318e49a113 100644
--- a/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro
+++ b/tests/auto/corelib/io/qfilesystemwatcher/qfilesystemwatcher.pro
@@ -3,3 +3,5 @@ TARGET = tst_qfilesystemwatcher
QT = core testlib
SOURCES = tst_qfilesystemwatcher.cpp
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+CONFIG += insignificant_test # QTBUG-33574
diff --git a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
index 1f57e38b44..4fcc46efab 100644
--- a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
+++ b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp
@@ -361,7 +361,7 @@ void tst_QIpAddress::parseIp6()
#endif
Ip6 result;
- bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
+ bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0;
QVERIFY(ok);
QCOMPARE(result, expected);
}
@@ -441,7 +441,7 @@ void tst_QIpAddress::invalidParseIp6()
#endif
Ip6 result;
- bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
+ bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0;
QVERIFY(!ok);
}
diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
index c0bf77cfb2..fdb29b60d8 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
@@ -77,7 +77,7 @@ void tst_QLockFile::initTestCase()
QString testdata_dir = QFileInfo(QFINDTESTDATA("qlockfiletesthelper")).absolutePath();
QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir));
m_helperApp = "qlockfiletesthelper/qlockfile_test_helper";
-#endif
+#endif // !QT_NO_PROCESS
}
void tst_QLockFile::lockUnlock()
@@ -111,6 +111,9 @@ void tst_QLockFile::lockUnlock()
void tst_QLockFile::lockOutOtherProcess()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
// Lock
const QString fileName = dir.path() + "/lockOtherProcess";
QLockFile lockFile(fileName);
@@ -132,6 +135,7 @@ void tst_QLockFile::lockOutOtherProcess()
QCOMPARE(ret, int(QLockFile::NoError));
// Lock doesn't survive process though (on clean exit)
QVERIFY(!QFile::exists(fileName));
+#endif // !QT_NO_PROCESS
}
static QLockFile::LockError tryLockFromThread(const QString &fileName)
@@ -228,6 +232,9 @@ void tst_QLockFile::staleLockFromCrashedProcess_data()
void tst_QLockFile::staleLockFromCrashedProcess()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
QFETCH(int, staleLockTime);
const QString fileName = dir.path() + "/staleLockFromCrashedProcess";
@@ -245,10 +252,14 @@ void tst_QLockFile::staleLockFromCrashedProcess()
QVERIFY(secondLock.tryLock());
#endif
QCOMPARE(int(secondLock.error()), int(QLockFile::NoError));
+#endif // !QT_NO_PROCESS
}
void tst_QLockFile::staleShortLockFromBusyProcess()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
const QString fileName = dir.path() + "/staleLockFromBusyProcess";
QProcess proc;
@@ -274,10 +285,14 @@ void tst_QLockFile::staleShortLockFromBusyProcess()
proc.waitForFinished();
QVERIFY(secondLock.tryLock());
+#endif // !QT_NO_PROCESS
}
void tst_QLockFile::staleLongLockFromBusyProcess()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
const QString fileName = dir.path() + "/staleLockFromBusyProcess";
QProcess proc;
@@ -297,6 +312,7 @@ void tst_QLockFile::staleLongLockFromBusyProcess()
QVERIFY(!secondLock.removeStaleLockFile());
proc.waitForFinished();
+#endif // !QT_NO_PROCESS
}
static QString tryStaleLockFromThread(const QString &fileName)
@@ -326,6 +342,9 @@ static QString tryStaleLockFromThread(const QString &fileName)
void tst_QLockFile::staleLockRace()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
// Multiple threads notice a stale lock at the same time
// Only one thread should delete it, otherwise a race will ensue
const QString fileName = dir.path() + "/sharedFile";
@@ -341,6 +360,7 @@ void tst_QLockFile::staleLockRace()
synchronizer.waitForFinished();
foreach (const QFuture<QString> &future, synchronizer.futures())
QVERIFY2(future.result().isEmpty(), qPrintable(future.result()));
+#endif // !QT_NO_PROCESS
}
void tst_QLockFile::noPermissions()
diff --git a/tests/auto/corelib/io/qloggingcategory/qloggingcategory.pro b/tests/auto/corelib/io/qloggingcategory/qloggingcategory.pro
new file mode 100644
index 0000000000..8492daefc1
--- /dev/null
+++ b/tests/auto/corelib/io/qloggingcategory/qloggingcategory.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+TARGET = tst_qloggingcategory
+
+CONFIG += testcase
+QT = core core-private testlib
+
+SOURCES += tst_qloggingcategory.cpp
diff --git a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp
new file mode 100644
index 0000000000..7ddb221402
--- /dev/null
+++ b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp
@@ -0,0 +1,818 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest>
+#include <QMutexLocker>
+#include <QLoggingCategory>
+
+Q_LOGGING_CATEGORY(TST_LOG, "tst.log")
+Q_LOGGING_CATEGORY(TST_LOG1, "tst.log1")
+Q_LOGGING_CATEGORY(Digia_Oslo_Office_com, "Digia.Oslo.Office.com")
+Q_LOGGING_CATEGORY(Digia_Oulu_Office_com, "Digia.Oulu.Office.com")
+Q_LOGGING_CATEGORY(Digia_Berlin_Office_com, "Digia.Berlin.Office.com")
+
+QT_USE_NAMESPACE
+
+QtMessageHandler oldMessageHandler;
+QString logMessage;
+bool multithreadtest = false;
+QStringList threadtest;
+QMutex threadmutex;
+bool usedefaultformat = false;
+
+QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context,
+ const QString &str)
+{
+ QByteArray message;
+ if (!usedefaultformat) {
+ message.append(context.category);
+ switch (type) {
+ case QtDebugMsg: message.append(".debug"); break;
+ case QtWarningMsg: message.append(".warning"); break;
+ case QtCriticalMsg:message.append(".critical"); break;
+ case QtFatalMsg: message.append(".fatal"); break;
+ }
+ message.append(": ");
+ message.append(qPrintable(str));
+ } else {
+ message.append(qPrintable(str));
+ }
+
+ return message.simplified();
+}
+
+static void myCustomMessageHandler(QtMsgType type,
+ const QMessageLogContext &context,
+ const QString &msg)
+{
+ QMutexLocker locker(&threadmutex);
+ logMessage = qMyMessageFormatString(type, context, msg);
+ if (multithreadtest)
+ threadtest.append(logMessage);
+}
+
+class Configuration
+{
+public:
+ Configuration()
+ {
+ }
+
+ void addKey(const QString &key, bool val){
+ // Old key values gets updated
+ _values.insert(key, (val ? "true" : "false"));
+ if (!_configitemEntryOrder.contains(key))
+ _configitemEntryOrder.append(key);
+ }
+
+ void addKey(const QString &key, const QString &val){
+ // Old key values gets updated
+ _values.insert(key, val);
+ if (!_configitemEntryOrder.contains(key))
+ _configitemEntryOrder.append(key);
+ }
+
+ QByteArray array()
+ {
+ QString ret;
+ QTextStream out(&ret);
+ for (int a = 0; a < _configitemEntryOrder.count(); a++) {
+ out << _configitemEntryOrder[a]
+ << " = "
+ << _values.value(_configitemEntryOrder[a]) << endl;
+ }
+ out.flush();
+ return ret.toLatin1();
+ }
+
+ void clear()
+ {
+ _values.clear();
+ _configitemEntryOrder.clear();
+ }
+
+private:
+ QMap<QString, QString> _values;
+ QStringList _configitemEntryOrder;
+};
+
+static Configuration configuration1;
+static Configuration configuration2;
+
+class LogThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ LogThread(const QString &logtext, Configuration *configuration)
+ : _logtext(logtext), _configuration(configuration)
+ {}
+protected:
+ void run()
+ {
+ for (int i = 0; i < 2000; i++) {
+ _configuration->addKey("Digia*", true);
+ QByteArray arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Oslo_Office_com) << "Oslo " << _logtext << " :true";
+ _configuration->addKey("Digia*", false);
+ arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Oslo_Office_com) << "Oslo " << _logtext << " :false";
+
+ _configuration->addKey("Digia*", true);
+ arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Berlin_Office_com) << "Berlin " << _logtext << " :true";
+ _configuration->addKey("Digia*", false);
+ arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Berlin_Office_com) << "Berlin " << _logtext << " :false";
+
+ _configuration->addKey("Digia*", true);
+ arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Oulu_Office_com) << "Oulu " << _logtext << " :true";
+ _configuration->addKey("Digia*", false);
+ arr = _configuration->array();
+ QLoggingCategory::setFilterRules(arr);
+ qCDebug(Digia_Oulu_Office_com) << "Oulu " << _logtext << " :false";
+ }
+ }
+
+public:
+ QString _logtext;
+ Configuration *_configuration;
+};
+
+inline QString cleanLogLine(const QString &qstring)
+{
+ QString buf = qstring;
+ buf.remove("../");
+ buf.remove("qlog/");
+ QString ret;
+ for (int i = 0; i < buf.length(); i++) {
+ if (buf[i] >= '!' && buf[i] <= 'z')
+ ret += buf[i];
+ }
+ return ret;
+}
+
+
+QStringList customCategoryFilterArgs;
+static void customCategoryFilter(QLoggingCategory *category)
+{
+ customCategoryFilterArgs << QLatin1String(category->categoryName());
+ // invert debug
+ category->setEnabled(QtDebugMsg, !category->isEnabled(QtDebugMsg));
+}
+
+class tst_QLogging : public QObject
+{
+ Q_OBJECT
+
+private:
+ Configuration *_config;
+ QStringList logEntries;
+
+private slots:
+ void initTestCase()
+ {
+ qputenv("QT_MESSAGE_PATTERN", QByteArray("%{category}: %{type},%{message}"));
+ oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler);
+ // Create configuration
+ _config = new Configuration();
+ }
+
+ void QLoggingCategory_categoryName()
+ {
+ logMessage.clear();
+ QCOMPARE(QString::fromLatin1(QLoggingCategory::defaultCategory().categoryName()),
+ QStringLiteral("default"));
+
+ QLoggingCategory defaultCategory("default");
+ QCOMPARE(QString::fromLatin1(defaultCategory.categoryName()),
+ QStringLiteral("default"));
+
+ QLoggingCategory nullCategory(0);
+ QCOMPARE(QByteArray(nullCategory.categoryName()), QByteArray("default"));
+
+ // we rely on the same pointer for any "default" category
+ QCOMPARE(QLoggingCategory::defaultCategory().categoryName(),
+ defaultCategory.categoryName());
+ QCOMPARE(defaultCategory.categoryName(),
+ nullCategory.categoryName());
+
+ QLoggingCategory customCategory("custom");
+ QCOMPARE(QByteArray(customCategory.categoryName()), QByteArray("custom"));
+
+ QLoggingCategory emptyCategory("");
+ QCOMPARE(QByteArray(emptyCategory.categoryName()), QByteArray(""));
+
+ // make sure nothing has printed warnings
+ QVERIFY(logMessage.isEmpty());
+ }
+
+ void QLoggingCategory_isEnabled()
+ {
+ logMessage.clear();
+
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), true);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtDebugMsg), true);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtWarningMsg>(), true);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtWarningMsg), true);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtCriticalMsg>(), true);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled(QtCriticalMsg), true);
+
+ QLoggingCategory defaultCategory("default");
+ QCOMPARE(defaultCategory.isEnabled<QtDebugMsg>(), true);
+ QCOMPARE(defaultCategory.isEnabled(QtDebugMsg), true);
+ QCOMPARE(defaultCategory.isEnabled<QtWarningMsg>(), true);
+ QCOMPARE(defaultCategory.isEnabled(QtWarningMsg), true);
+ QCOMPARE(defaultCategory.isEnabled<QtCriticalMsg>(), true);
+ QCOMPARE(defaultCategory.isEnabled(QtCriticalMsg), true);
+
+ QLoggingCategory customCategory("custom");
+ QCOMPARE(customCategory.isEnabled<QtDebugMsg>(), false);
+ QCOMPARE(customCategory.isEnabled(QtDebugMsg), false);
+ QCOMPARE(customCategory.isEnabled<QtWarningMsg>(), true);
+ QCOMPARE(customCategory.isEnabled(QtWarningMsg), true);
+ QCOMPARE(customCategory.isEnabled<QtCriticalMsg>(), true);
+ QCOMPARE(customCategory.isEnabled(QtCriticalMsg), true);
+
+ // make sure nothing has printed warnings
+ QVERIFY(logMessage.isEmpty());
+ }
+
+ void QLoggingCategory_setEnabled()
+ {
+ logMessage.clear();
+
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), true);
+
+ QLoggingCategory::defaultCategory().setEnabled(QtDebugMsg, false);
+ QCOMPARE(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>(), false);
+ QLoggingCategory::defaultCategory().setEnabled(QtDebugMsg, true);
+
+ // make sure nothing has printed warnings
+ QVERIFY(logMessage.isEmpty());
+
+ }
+
+ void QLoggingCategory_installFilter()
+ {
+ QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
+
+ QLoggingCategory::CategoryFilter defaultFilter =
+ QLoggingCategory::installFilter(customCategoryFilter);
+ QVERIFY(defaultFilter);
+ customCategoryFilterArgs.clear();
+ QVERIFY(!QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
+
+ QLoggingCategory cat("custom");
+ QCOMPARE(customCategoryFilterArgs, QStringList() << "custom");
+ QVERIFY(cat.isEnabled<QtDebugMsg>());
+ customCategoryFilterArgs.clear();
+
+ // install default filter
+ QLoggingCategory::CategoryFilter currentFilter =
+ QLoggingCategory::installFilter(defaultFilter);
+ QCOMPARE((void*)currentFilter, (void*)customCategoryFilter);
+ QCOMPARE(customCategoryFilterArgs.size(), 0);
+
+ QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
+ QVERIFY(!cat.isEnabled<QtDebugMsg>());
+
+ // install default filter
+ currentFilter =
+ QLoggingCategory::installFilter(0);
+ QCOMPARE((void*)defaultFilter, (void*)currentFilter);
+ QCOMPARE(customCategoryFilterArgs.size(), 0);
+
+ QVERIFY(QLoggingCategory::defaultCategory().isEnabled<QtDebugMsg>());
+ QVERIFY(!cat.isEnabled<QtDebugMsg>());
+ }
+
+ void qDebugMacros()
+ {
+ QString buf;
+
+ // Check default debug
+ buf = QStringLiteral("default.debug: Check debug with no filter active");
+ qDebug("%s", "Check debug with no filter active");
+ QCOMPARE(logMessage, buf);
+
+ // Check default warning
+ buf = QStringLiteral("default.warning: Check warning with no filter active");
+ qWarning("%s", "Check warning with no filter active");
+ QCOMPARE(logMessage, buf);
+
+ // Check default critical
+ buf = QStringLiteral("default.critical: Check critical with no filter active");
+ qCritical("%s", "Check critical with no filter active");
+ QCOMPARE(logMessage, buf);
+
+ // install filter (inverts rules for qtdebug)
+ QLoggingCategory::installFilter(customCategoryFilter);
+
+ // Check default debug
+ logMessage.clear();
+ qDebug("%s", "Check debug with filter active");
+ QCOMPARE(logMessage, QString());
+
+ // reset to default filter
+ QLoggingCategory::installFilter(0);
+
+ // Check default debug
+ buf = QStringLiteral("default.debug: Check debug with no filter active");
+ qDebug("%s", "Check debug with no filter active");
+ QCOMPARE(logMessage, buf);
+ }
+
+ void qCDebugMacros()
+ {
+ QString buf;
+
+ QLoggingCategory defaultCategory("default");
+ // Check default debug
+ buf = QStringLiteral("default.debug: Check debug with no filter active");
+ qCDebug(defaultCategory) << "Check debug with no filter active";
+ QCOMPARE(logMessage, buf);
+
+ // Check default warning
+ buf = QStringLiteral("default.warning: Check warning with no filter active");
+ qCWarning(defaultCategory) << "Check warning with no filter active";
+ QCOMPARE(logMessage, buf);
+
+ // Check default critical
+ buf = QStringLiteral("default.critical: Check critical with no filter active");
+ qCCritical(defaultCategory) << "Check critical with no filter active";
+ QCOMPARE(logMessage, buf);
+
+
+ QLoggingCategory customCategory("custom");
+ // Check custom debug
+ logMessage.clear();
+ qCDebug(customCategory) << "Check debug with no filter active";
+ QCOMPARE(logMessage, QString());
+
+ // Check custom warning
+ buf = QStringLiteral("custom.warning: Check warning with no filter active");
+ qCWarning(customCategory) << "Check warning with no filter active";
+ QCOMPARE(logMessage, buf);
+
+ // Check custom critical
+ buf = QStringLiteral("custom.critical: Check critical with no filter active");
+ qCCritical(customCategory) << "Check critical with no filter active";
+ QCOMPARE(logMessage, buf);
+
+ // install filter (inverts rules for qtdebug)
+ QLoggingCategory::installFilter(customCategoryFilter);
+
+ // Check custom debug
+ buf = QStringLiteral("custom.debug: Check debug with filter active");
+ qCDebug(customCategory) << "Check debug with filter active";
+ QCOMPARE(logMessage, buf);
+
+ // reset to default filter
+ QLoggingCategory::installFilter(0);
+
+ // Check custom debug
+ logMessage.clear();
+ qCDebug(customCategory) << "Check debug with no filter active";
+ QCOMPARE(logMessage, QString());
+ }
+
+ void checkLegacyMessageLogger()
+ {
+ usedefaultformat = true;
+ // This should just not crash.
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug() << "checkLegacyMessageLogger1";
+ QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger1"));
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning() << "checkLegacyMessageLogger2";
+ QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger2"));
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() << "checkLegacyMessageLogger3";
+ QCOMPARE(logMessage, QStringLiteral("checkLegacyMessageLogger3"));
+ usedefaultformat = false;
+ }
+
+ // Check the Debug, Warning and critical without having category active. should be active.
+ void checkNoCategoryLogActive()
+ {
+ // Check default debug
+ QString buf = QStringLiteral("default.debug: Check default Debug with no log active");
+ qDebug() << "Check default Debug with no log active";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check default warning
+ buf = QStringLiteral("default.warning: Check default Warning with no log active");
+ qWarning() << "Check default Warning with no log active";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check default critical
+ buf = QStringLiteral("default.critical: Check default Critical with no log active");
+ qCritical() << "Check default Critical with no log active";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check category debug
+ logMessage = "should not change";
+ buf = logMessage;
+ qCDebug(TST_LOG) << "Check category Debug with no log active";
+ QCOMPARE(logMessage, buf);
+
+ // Check default warning
+ buf = QStringLiteral("tst.log.warning: Check category Warning with no log active");
+ qCWarning(TST_LOG) << "Check category Warning with no log active";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check default critical
+ buf = QStringLiteral("tst.log.critical: Check category Critical with no log active");
+ qCCritical(TST_LOG) << "Check category Critical with no log active";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ }
+
+ void writeCategoryLogs()
+ {
+ usedefaultformat = false;
+ // Activate TST_LOG category
+ logMessage = "";
+ _config->addKey("tst.log", true);
+ QLoggingCategory::setFilterRules(_config->array());
+ QString buf = QStringLiteral("tst.log.debug: Check for default messagePattern");
+ qCDebug(TST_LOG) << "Check for default messagePattern";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Activate TST_LOG category with default enabled function info
+ _config->addKey("tst.log1", true);
+ QLoggingCategory::setFilterRules(_config->array());
+ qCDebug(TST_LOG) << "1";
+ buf = QStringLiteral("tst.log.debug: 1");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Write out all different types
+ qCDebug(TST_LOG) << "DebugType";
+ buf = QStringLiteral("tst.log.debug: DebugType");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCWarning(TST_LOG) << "WarningType";
+ buf = QStringLiteral("tst.log.warning: WarningType");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCCritical(TST_LOG) << "CriticalType";
+ buf = QStringLiteral("tst.log.critical: CriticalType");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ }
+
+ void checkLegacyLogs()
+ {
+ logMessage = "";
+ qDebug() << "DefaultDebug";
+ QString buf = QStringLiteral("default.debug: DefaultDebug");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // debug off by default, warning and critical are on
+ qWarning() << "DefaultWarning";
+ buf = QStringLiteral("default.warning: DefaultWarning");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical";
+ buf = QStringLiteral("default.critical: DefaultCritical");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Enable debug
+ _config->addKey("default.debug", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qDebug() << "DefaultDebug1";
+ buf = QStringLiteral("default.debug: DefaultDebug1");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qWarning() << "DefaultWarning1";
+ buf = QStringLiteral("default.warning: DefaultWarning1");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical1";
+ buf = QStringLiteral("default.critical: DefaultCritical1");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Disable warning
+ _config->addKey("default.warning", false);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qDebug() << "DefaultDebug2";
+ buf = QStringLiteral("default.debug: DefaultDebug2");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ logMessage = "no change";
+ qWarning() << "DefaultWarning2";
+ buf = QStringLiteral("no change");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical2";
+ buf = QStringLiteral("default.critical: DefaultCritical2");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Disable critical
+ _config->addKey("default.critical", false);
+ _config->addKey("default.debug", false);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ logMessage = "no change";
+ qDebug() << "DefaultDebug3";
+ buf = QStringLiteral("no change");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qWarning() << "DefaultWarning3";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical3";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Enable default logs
+ _config->addKey("default.critical", true);
+ _config->addKey("default.warning", true);
+ _config->addKey("default.debug", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ // Ensure all are on
+ qDebug() << "DefaultDebug4";
+ buf = QStringLiteral("default.debug: DefaultDebug4");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qWarning() << "DefaultWarning4";
+ buf = QStringLiteral("default.warning: DefaultWarning4");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical4";
+ buf = QStringLiteral("default.critical: DefaultCritical4");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Disable default log
+ _config->addKey("default", false);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ // Ensure all are off
+ logMessage = "no change";
+ buf = QStringLiteral("no change");
+ qDebug() << "DefaultDebug5";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qWarning() << "DefaultWarning5";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCritical() << "DefaultCritical5";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Reset
+ _config->clear();
+ QLoggingCategory::setFilterRules(_config->array());
+ }
+
+ void checkFiltering()
+ {
+ // Enable default logs
+ _config->clear();
+ _config->addKey("Digia.Oslo.Office.com", false);
+ _config->addKey("Digia.Oulu.Office.com", false);
+ _config->addKey("Digia.Berlin.Office.com", false);
+ _config->addKey("MessagePattern", QString("%{category}: %{message}"));
+ QLoggingCategory::setFilterRules(_config->array());
+
+ logMessage = "no change";
+ QString buf = QStringLiteral("no change");
+ qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 1";
+ qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 1";
+ qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 1";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ _config->addKey("Digia.Oslo.Office.com", true);
+ _config->addKey("Digia.Oulu.Office.com", true);
+ _config->addKey("Digia.Berlin.Office.com", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 2";
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Digia.Oslo.Office.com 2");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 2";
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Digia.Oulu.Office.com 2");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 2";
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Digia.Berlin.Office.com 2");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check right filter
+ _config->addKey("Digia.Oslo.Office.com", false);
+ _config->addKey("Digia.Oulu.Office.com", false);
+ _config->addKey("Digia.Berlin.Office.com", false);
+ _config->addKey("*Office.com*", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qCDebug(Digia_Oslo_Office_com) << "Digia.Oslo.Office.com 3";
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Digia.Oslo.Office.com 3");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCDebug(Digia_Oulu_Office_com) << "Digia.Oulu.Office.com 3";
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Digia.Oulu.Office.com 3");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCDebug(Digia_Berlin_Office_com) << "Digia.Berlin.Office.com 3";
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Digia.Berlin.Office.com 3");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check left filter
+ _config->addKey("*Office.com*", false);
+ _config->addKey("*Office.com.debug", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 4";
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 4");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ logMessage = "no change";
+ buf = QStringLiteral("no change");
+ qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 4";
+ qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 4";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check right filter
+ _config->addKey("*Office.com.debug", false);
+ _config->addKey("Digia.*", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 5";
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 5");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 5";
+ buf = QStringLiteral("Digia.Oulu.Office.com.warning: Warning: Digia.Oulu.Office.com 5");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 5";
+ buf = QStringLiteral("Digia.Berlin.Office.com.critical: Critical: Digia.Berlin.Office.com 5");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // Check mid filter
+ _config->addKey("Digia.*", false);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ logMessage = "no change";
+ buf = QStringLiteral("no change");
+ qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 6";
+ qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 6";
+ qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 6";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ _config->addKey("*.Office.*", true);
+ QLoggingCategory::setFilterRules(_config->array());
+
+ qCDebug(Digia_Oslo_Office_com) << "Debug: Digia.Oslo.Office.com 7";
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Debug: Digia.Oslo.Office.com 7");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCWarning(Digia_Oulu_Office_com) << "Warning: Digia.Oulu.Office.com 7";
+ buf = QStringLiteral("Digia.Oulu.Office.com.warning: Warning: Digia.Oulu.Office.com 7");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ qCCritical(Digia_Berlin_Office_com) << "Critical: Digia.Berlin.Office.com 7";
+ buf = QStringLiteral("Digia.Berlin.Office.com.critical: Critical: Digia.Berlin.Office.com 7");
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ }
+
+ void checkLogWithCategoryObject()
+ {
+ _config->clear();
+ _config->addKey("LoggingCategoryObject", true);
+ QLoggingCategory *pcategorybject = 0;
+ QLoggingCategory::setFilterRules(_config->array());
+ {
+ QLoggingCategory mycategoryobject("LoggingCategoryObject");
+ pcategorybject = &mycategoryobject;
+ logMessage = "no change";
+
+ QString buf = QStringLiteral("LoggingCategoryObject.debug: My Category Object");
+ qCDebug(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ buf = QStringLiteral("LoggingCategoryObject.warning: My Category Object");
+ qCWarning(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ buf = QStringLiteral("LoggingCategoryObject.critical: My Category Object");
+ qCCritical(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ QLoggingCategory mycategoryobject2("LoggingCategoryObject");
+ buf = QStringLiteral("LoggingCategoryObject.debug: My Category Object");
+ qCDebug(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ buf = QStringLiteral("LoggingCategoryObject.warning: My Category Object");
+ qCWarning(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ buf = QStringLiteral("LoggingCategoryObject.critical: My Category Object");
+ qCCritical(mycategoryobject) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ }
+ }
+
+ void checkEmptyCategoryName()
+ {
+ // "" -> custom category
+ QLoggingCategory mycategoryobject1("");
+ logMessage = "no change";
+ QString buf = QStringLiteral("no change");
+ qCDebug(mycategoryobject1) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+
+ // 0 -> default category
+ QLoggingCategory mycategoryobject2(0);
+ buf = QStringLiteral("default.debug:MyCategoryObject");
+ qCDebug(mycategoryobject2) << "My Category Object";
+ QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf));
+ }
+
+ void checkMultithreading()
+ {
+ multithreadtest = true;
+ // Init two configurations, one for each thread
+ configuration1.addKey("Digia*", true);
+ configuration2.addKey("Digia*", true);
+ QByteArray arr = configuration1.array();
+ QLoggingCategory::setFilterRules(arr);
+
+ LogThread thgread1(QString("from Thread 1"), &configuration1);
+ LogThread thgread2(QString("from Thread 2"), &configuration2);
+
+ // Writing out stuff from 2 different threads into the same areas
+ thgread1.start();
+ thgread2.start();
+ thgread1.wait();
+ thgread2.wait();
+
+ // Check if each log line is complete
+ QStringList compareagainst;
+ QString buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 1\" :true");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 1\" :true");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 1\" :true");
+ compareagainst.append(cleanLogLine(buf));
+
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 1\" :false");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 1\" :false");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 1\" :false");
+ compareagainst.append(cleanLogLine(buf));
+
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 2\" :true");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 2\" :true");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 2\" :true");
+ compareagainst.append(cleanLogLine(buf));
+
+ buf = QStringLiteral("Digia.Oslo.Office.com.debug: Oslo \"from Thread 2\" :false");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Oulu.Office.com.debug: Oulu \"from Thread 2\" :false");
+ compareagainst.append(cleanLogLine(buf));
+ buf = QStringLiteral("Digia.Berlin.Office.com.debug: Berlin \"from Thread 2\" :false");
+ compareagainst.append(cleanLogLine(buf));
+
+ for (int i = 0; i < threadtest.count(); i++) {
+ if (!compareagainst.contains(cleanLogLine(threadtest[i]))){
+ fprintf(stdout, "%s\r\n", threadtest[i].toLatin1().constData());
+ QVERIFY2(false, "Multithread log is not complete!");
+ }
+ }
+ }
+
+ void cleanupTestCase()
+ {
+ delete _config;
+ qInstallMessageHandler(oldMessageHandler);
+ }
+};
+
+QTEST_MAIN(tst_QLogging)
+
+#include "tst_qloggingcategory.moc"
diff --git a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp
index f1df6187d0..157e42b447 100644
--- a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp
+++ b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp
@@ -49,6 +49,7 @@
#include <QtCore/QtCore>
#include <QtCore/QtDebug>
+#include <QtCore/QLoggingCategory>
#include <QtTest/QtTest>
class tst_QNoDebug: public QObject
@@ -61,18 +62,24 @@ private slots:
void tst_QNoDebug::noDebugOutput() const
{
+ QLoggingCategory cat("custom");
// should do nothing
qDebug() << "foo";
+ qCDebug(cat) << "foo";
// qWarning still works, though
QTest::ignoreMessage(QtWarningMsg, "bar ");
+ QTest::ignoreMessage(QtWarningMsg, "custom-bar ");
qWarning() << "bar";
+ qCWarning(cat) << "custom-bar";
}
void tst_QNoDebug::streaming() const
{
QDateTime dt(QDate(1,2,3),QTime(4,5,6));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QDateTime(\"%1\") ").arg(dt.toString())));
+ QString debugString = dt.toString(QStringLiteral("yyyy-MM-dd HH:mm:ss.zzz t"))
+ + QStringLiteral(" Qt::LocalTime");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QDateTime(\"%1\") ").arg(debugString)));
qWarning() << dt;
}
diff --git a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
index e69ae173f4..42394f6414 100644
--- a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
+++ b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp
@@ -39,30 +39,49 @@
**
****************************************************************************/
+#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
-int main()
+#include <stdlib.h>
+
+int main(int argc, char **argv)
{
+ QCoreApplication app(argc, argv);
+
+ if (argc < 3)
+ return 13;
+
#ifndef QT_NO_PROCESS
QProcess process;
- process.setProcessChannelMode(QProcess::ForwardedChannels);
- if (process.processChannelMode() != QProcess::ForwardedChannels)
- return -1;
- process.start("testProcessEcho/testProcessEcho");
+ QProcess::ProcessChannelMode mode = (QProcess::ProcessChannelMode)atoi(argv[1]);
+ process.setProcessChannelMode(mode);
+ if (process.processChannelMode() != mode)
+ return 1;
- if (!process.waitForStarted(5000))
- return -1;
+ QProcess::InputChannelMode inmode = (QProcess::InputChannelMode)atoi(argv[2]);
+ process.setInputChannelMode(inmode);
+ if (process.inputChannelMode() != inmode)
+ return 11;
- if (process.write("forwarded\n") != 10)
- return -1;
+ process.start("testProcessEcho2/testProcessEcho2");
- process.waitForReadyRead(250);
- if (process.bytesAvailable() != 0)
- return -1;
+ if (!process.waitForStarted(5000))
+ return 2;
+
+ if (inmode == QProcess::ManagedInputChannel && process.write("forwarded") != 9)
+ return 3;
process.closeWriteChannel();
- process.waitForFinished(5000);
+ if (!process.waitForFinished(5000))
+ return 4;
+
+ if ((mode == QProcess::ForwardedOutputChannel || mode == QProcess::ForwardedChannels)
+ && !process.readAllStandardOutput().isEmpty())
+ return 5;
+ if ((mode == QProcess::ForwardedErrorChannel || mode == QProcess::ForwardedChannels)
+ && !process.readAllStandardError().isEmpty())
+ return 6;
#endif
return 0;
}
diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
index 7a3f6837f8..d248f022ed 100644
--- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
+++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp
@@ -107,8 +107,8 @@ private slots:
void softExitInSlots_data();
void softExitInSlots();
void mergedChannels();
+ void forwardedChannels_data();
void forwardedChannels();
- void forwardedChannelsOutput();
void atEnd();
void atEnd2();
void waitForFinishedWithTimeout();
@@ -122,6 +122,7 @@ private slots:
void setStandardInputFile();
void setStandardOutputFile_data();
void setStandardOutputFile();
+ void setStandardOutputFile2();
void setStandardOutputProcess_data();
void setStandardOutputProcess();
void removeFileWhileProcessIsRunning();
@@ -1089,36 +1090,55 @@ void tst_QProcess::mergedChannels()
//-----------------------------------------------------------------------------
#ifndef Q_OS_WINCE
// Reading and writing to a process is not supported on Qt/CE
-void tst_QProcess::forwardedChannels()
-{
- QProcess process;
- process.setReadChannelMode(QProcess::ForwardedChannels);
- QCOMPARE(process.readChannelMode(), QProcess::ForwardedChannels);
-
- process.start("testProcessEcho2/testProcessEcho2");
- QVERIFY(process.waitForStarted(5000));
- QCOMPARE(process.write("forwarded\n"), qlonglong(10));
- QVERIFY(!process.waitForReadyRead(250));
- QCOMPARE(process.bytesAvailable(), qlonglong(0));
+void tst_QProcess::forwardedChannels_data()
+{
+ QTest::addColumn<int>("mode");
+ QTest::addColumn<int>("inmode");
+ QTest::addColumn<QByteArray>("outdata");
+ QTest::addColumn<QByteArray>("errdata");
- process.closeWriteChannel();
- QVERIFY(process.waitForFinished(5000));
+ QTest::newRow("separate") << int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel)
+ << QByteArray() << QByteArray();
+ QTest::newRow("forwarded") << int(QProcess::ForwardedChannels) << int(QProcess::ManagedInputChannel)
+ << QByteArray("forwarded") << QByteArray("forwarded");
+ QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel) << int(QProcess::ManagedInputChannel)
+ << QByteArray("forwarded") << QByteArray();
+ QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ManagedInputChannel)
+ << QByteArray() << QByteArray("forwarded");
+ QTest::newRow("fwdinput") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ForwardedInputChannel)
+ << QByteArray() << QByteArray("input");
}
-#endif
-#ifndef Q_OS_WINCE
-// Reading and writing to a process is not supported on Qt/CE
-void tst_QProcess::forwardedChannelsOutput()
+void tst_QProcess::forwardedChannels()
{
+ QFETCH(int, mode);
+ QFETCH(int, inmode);
+ QFETCH(QByteArray, outdata);
+ QFETCH(QByteArray, errdata);
+
QProcess process;
- process.start("testForwarding/testForwarding");
+ process.start("testForwarding/testForwarding", QStringList() << QString::number(mode) << QString::number(inmode));
QVERIFY(process.waitForStarted(5000));
+ QCOMPARE(process.write("input"), 5);
+ process.closeWriteChannel();
QVERIFY(process.waitForFinished(5000));
- QVERIFY(!process.exitCode());
- QByteArray data = process.readAll();
- QVERIFY(!data.isEmpty());
- QVERIFY(data.contains("forwarded"));
+ const char *err;
+ switch (process.exitCode()) {
+ case 0: err = "ok"; break;
+ case 1: err = "processChannelMode is wrong"; break;
+ case 11: err = "inputChannelMode is wrong"; break;
+ case 2: err = "failed to start"; break;
+ case 3: err = "failed to write"; break;
+ case 4: err = "did not finish"; break;
+ case 5: err = "unexpected stdout"; break;
+ case 6: err = "unexpected stderr"; break;
+ case 13: err = "parameter error"; break;
+ default: err = "unknown exit code"; break;
+ }
+ QVERIFY2(!process.exitCode(), err);
+ QCOMPARE(process.readAllStandardOutput(), outdata);
+ QCOMPARE(process.readAllStandardError(), errdata);
}
#endif
@@ -1868,6 +1888,13 @@ void tst_QProcess::setStandardInputFile()
QByteArray all = process.readAll();
QCOMPARE(all.size(), int(sizeof data) - 1); // testProcessEcho drops the ending \0
QVERIFY(all == data);
+
+ QProcess process2;
+ process2.setStandardInputFile(QProcess::nullDevice());
+ process2.start("testProcessEcho/testProcessEcho");
+ QPROCESS_VERIFY(process2, waitForFinished());
+ all = process2.readAll();
+ QCOMPARE(all.size(), 0);
}
#endif
@@ -1902,6 +1929,23 @@ void tst_QProcess::setStandardOutputFile_data()
<< true;
}
+//-----------------------------------------------------------------------------
+#ifndef Q_OS_WINCE
+void tst_QProcess::setStandardOutputFile2()
+{
+ static const char testdata[] = "Test data.";
+
+ QProcess process;
+ process.setStandardOutputFile(QProcess::nullDevice());
+ process.start("testProcessEcho2/testProcessEcho2");
+ process.write(testdata, sizeof testdata);
+ QPROCESS_VERIFY(process,waitForFinished());
+ QVERIFY(!process.bytesAvailable());
+
+ QVERIFY(!QFileInfo(QProcess::nullDevice()).isFile());
+}
+#endif
+
void tst_QProcess::setStandardOutputFile()
{
static const char data[] = "Original data. ";
diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
index 45f143b9fb..9d3519680c 100644
--- a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
+++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
@@ -43,10 +43,6 @@
#include <QObject>
#include <QProcessEnvironment>
-#ifdef QT_NO_PROCESS
-QTEST_NOOP_MAIN
-#else
-
class tst_QProcessEnvironment: public QObject
{
Q_OBJECT
@@ -322,4 +318,3 @@ void tst_QProcessEnvironment::putenv()
QTEST_MAIN(tst_QProcessEnvironment)
#include "tst_qprocessenvironment.moc"
-#endif
diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
index f94c8eac4f..b63dbc449c 100644
--- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
+++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
@@ -56,11 +56,14 @@
#define Q_XDG_PLATFORM
#endif
+const int MaxStandardLocation = QStandardPaths::GenericCacheLocation;
+
class tst_qstandardpaths : public QObject
{
Q_OBJECT
private slots:
+ void dump();
void testDefaultLocations();
void testCustomLocations();
void enableTestMode();
@@ -108,6 +111,39 @@ private:
QTemporaryDir m_globalAppTempDir;
};
+static const char * const enumNames[MaxStandardLocation + 1 - int(QStandardPaths::DesktopLocation)] = {
+ "DesktopLocation",
+ "DocumentsLocation",
+ "FontsLocation",
+ "ApplicationsLocation",
+ "MusicLocation",
+ "MoviesLocation",
+ "PicturesLocation",
+ "TempLocation",
+ "HomeLocation",
+ "DataLocation",
+ "CacheLocation",
+ "GenericDataLocation",
+ "RuntimeLocation",
+ "ConfigLocation",
+ "DownloadLocation",
+ "GenericCacheLocation"
+};
+
+void tst_qstandardpaths::dump()
+{
+#ifdef Q_XDG_PLATFORM
+ setDefaultLocations();
+#endif
+ // This is not a test. It merely dumps the output.
+ for (int i = QStandardPaths::DesktopLocation; i <= MaxStandardLocation; ++i) {
+ QStandardPaths::StandardLocation s = QStandardPaths::StandardLocation(i);
+ qDebug() << enumNames[i]
+ << QStandardPaths::writableLocation(s)
+ << QStandardPaths::standardLocations(s);
+ }
+}
+
void tst_qstandardpaths::testDefaultLocations()
{
#ifdef Q_XDG_PLATFORM
@@ -166,7 +202,7 @@ void tst_qstandardpaths::testCustomLocations()
void tst_qstandardpaths::enableTestMode()
{
QVERIFY(!QStandardPaths::isTestModeEnabled());
- QStandardPaths::enableTestMode(true);
+ QStandardPaths::setTestModeEnabled(true);
QVERIFY(QStandardPaths::isTestModeEnabled());
#ifdef Q_XDG_PLATFORM
@@ -204,7 +240,7 @@ void tst_qstandardpaths::enableTestMode()
// On Windows, what should "Program Files" become, in test mode?
//testLocations.insert(QStandardPaths::ApplicationsLocation, QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
- QStandardPaths::enableTestMode(false);
+ QStandardPaths::setTestModeEnabled(false);
for (LocationHash::const_iterator it = testLocations.constBegin(); it != testLocations.constEnd(); ++it)
QVERIFY2(QStandardPaths::writableLocation(it.key()) != it.value(), qPrintable(it.value()));
diff --git a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp
index 40621957ce..db2a5b53fd 100644
--- a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp
+++ b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp
@@ -40,13 +40,11 @@
****************************************************************************/
-#include <QtCore/QCoreApplication>
#include <QtCore/QTextStream>
-#include <QtCore/QDebug>
+#include <stdio.h>
-int main(int argc, char **argv)
+int main(int, char**)
{
- QCoreApplication a(argc, argv);
- qDebug() << QTextStream(stdin).readAll();
+ fprintf(stderr, "%s\n", QTextStream(stdin).readAll().toLatin1().constData());
return 0;
}
diff --git a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp
index e36a2aeda8..cb4e75c6a2 100644
--- a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp
+++ b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp
@@ -40,17 +40,16 @@
****************************************************************************/
-#include <QtCore/QCoreApplication>
#include <QtCore/QTextStream>
+#include <stdio.h>
-int main(int argc, char **argv)
+int main(int, char**)
{
- QCoreApplication a(argc, argv);
QTextStream qin(stdin);
if (!qin.atEnd()) {
- int a, b, c;
- qin >> a >> b >> c;
- qDebug("%d %d %d", a, b, c);
+ int a, b, c;
+ qin >> a >> b >> c;
+ fprintf(stderr, "%d %d %d\n", a, b, c);
}
return 0;
}
diff --git a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp
index 56c07f1590..c19e80bff3 100644
--- a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp
+++ b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp
@@ -1425,8 +1425,7 @@ void tst_QTextStream::readAllFromStdin()
stdinProcess.closeWriteChannel();
QVERIFY(stdinProcess.waitForFinished(5000));
- QChar quoteChar('"');
- QCOMPARE(stream.readAll(), QString::fromLatin1("%1hello world%2 \n").arg(quoteChar).arg(quoteChar));
+ QCOMPARE(stream.readAll(), QString::fromLatin1("hello world\n"));
}
// ------------------------------------------------------------------------------
diff --git a/tests/auto/corelib/io/qurl/qurl.pro b/tests/auto/corelib/io/qurl/qurl.pro
index a5e7130505..f65a9c688c 100644
--- a/tests/auto/corelib/io/qurl/qurl.pro
+++ b/tests/auto/corelib/io/qurl/qurl.pro
@@ -3,3 +3,5 @@ TARGET = tst_qurl
QT = core testlib concurrent
SOURCES = tst_qurl.cpp
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+mac: OBJECTIVE_SOURCES += tst_qurl_mac.mm
diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp
index 2a506ef8e2..2128d68485 100644
--- a/tests/auto/corelib/io/qurl/tst_qurl.cpp
+++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp
@@ -87,6 +87,7 @@ private slots:
void toLocalFile();
void fromLocalFile_data();
void fromLocalFile();
+ void macTypes();
void relative();
void compat_legacy();
void compat_constructor_01_data();
@@ -111,6 +112,8 @@ private slots:
void percentEncoding();
void swap();
void symmetry();
+ void ipvfuture_data();
+ void ipvfuture();
void ipv6_data();
void ipv6();
void ipv6_2_data();
@@ -146,6 +149,8 @@ private slots:
void stripTrailingSlash();
void hosts_data();
void hosts();
+ void hostFlags_data();
+ void hostFlags();
void setPort();
void toEncoded_data();
void toEncoded();
@@ -160,6 +165,8 @@ private slots:
void binaryData();
void fromUserInput_data();
void fromUserInput();
+ void fileName_data();
+ void fileName();
void isEmptyForEncodedUrl();
void toEncodedNotUsingUninitializedPath();
void emptyAuthorityRemovesExistingAuthority();
@@ -291,6 +298,8 @@ void tst_QUrl::comparison()
QVERIFY(url1 == url2);
QVERIFY(!(url1 < url2));
QVERIFY(!(url2 < url1));
+ QVERIFY(url1.matches(url2, QUrl::None));
+ QVERIFY(url1.matches(url2, QUrl::StripTrailingSlash));
// 6.2.2 Syntax-based Normalization
QUrl url3 = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D");
@@ -298,6 +307,22 @@ void tst_QUrl::comparison()
QEXPECT_FAIL("", "Normalization not implemented, will probably not be implemented like this", Continue);
QCOMPARE(url3, url4);
+ QUrl url3bis = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D/");
+ QUrl url3bisNoSlash = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D");
+ QUrl url4bis = QUrl::fromEncoded("example://a/.//b/../b/c//%7Bfoo%7D/");
+ QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments), url3bis);
+ QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments | QUrl::StripTrailingSlash), url3bisNoSlash);
+ QVERIFY(url3bis.matches(url4bis, QUrl::NormalizePathSegments));
+ QVERIFY(!url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments));
+ QVERIFY(url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments | QUrl::StripTrailingSlash));
+
+ QUrl url4EncodedDots = QUrl("example://a/.//b/%2E%2E%2F/b/c/");
+ QCOMPARE(url4EncodedDots.path(QUrl::PrettyDecoded), QString("/.//b/..%2F/b/c/"));
+ QCOMPARE(url4EncodedDots.path(QUrl::FullyDecoded), QString("/.//b/..//b/c/"));
+ QCOMPARE(QString::fromLatin1(url4EncodedDots.toEncoded()), QString::fromLatin1("example://a/.//b/..%2F/b/c/"));
+ QCOMPARE(url4EncodedDots.toString(), QString("example://a/.//b/..%2F/b/c/"));
+ QCOMPARE(url4EncodedDots.adjusted(QUrl::NormalizePathSegments).toString(), QString("example://a/b/..%2F/b/c/"));
+
// 6.2.2.1 Make sure hexdecimal characters in percent encoding are
// treated case-insensitively
QUrl url5;
@@ -312,6 +337,59 @@ void tst_QUrl::comparison()
url8.setEncodedQuery("a=c");
QVERIFY(url7 != url8);
QVERIFY(url7 < url8);
+
+ // Trailing slash difference
+ QUrl url9("http://qt-project.org/path/");
+ QUrl url9NoSlash("http://qt-project.org/path");
+ QVERIFY(!(url9 == url9NoSlash));
+ QVERIFY(!url9.matches(url9NoSlash, QUrl::None));
+ QVERIFY(url9.matches(url9NoSlash, QUrl::StripTrailingSlash));
+
+ // RemoveFilename
+ QUrl url10("http://qt-project.org/file");
+ QUrl url10bis("http://qt-project.org/otherfile");
+ QVERIFY(!(url10 == url10bis));
+ QVERIFY(!url10.matches(url10bis, QUrl::None));
+ QVERIFY(!url10.matches(url10bis, QUrl::StripTrailingSlash));
+ QVERIFY(url10.matches(url10bis, QUrl::RemoveFilename));
+
+ // RemoveAuthority
+ QUrl authUrl1("x://host/a/b");
+ QUrl authUrl2("x://host/a/");
+ QUrl authUrl3("x:/a/b");
+ QVERIFY(authUrl1.matches(authUrl2, QUrl::RemoveFilename));
+ QCOMPARE(authUrl1.adjusted(QUrl::RemoveAuthority), authUrl3.adjusted(QUrl::RemoveAuthority));
+ QVERIFY(authUrl1.matches(authUrl3, QUrl::RemoveAuthority));
+ QCOMPARE(authUrl2.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename), authUrl3.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename));
+ QVERIFY(authUrl2.matches(authUrl3, QUrl::RemoveAuthority | QUrl::RemoveFilename));
+ QVERIFY(authUrl3.matches(authUrl2, QUrl::RemoveAuthority | QUrl::RemoveFilename));
+
+ QUrl hostUrl1("file:/foo");
+ QUrl hostUrl2("file:///foo");
+ QVERIFY(hostUrl1 == hostUrl2);
+ QVERIFY(hostUrl1.matches(hostUrl2, QUrl::None));
+ QVERIFY(hostUrl1.matches(hostUrl2, QUrl::RemoveAuthority));
+
+ // RemovePassword
+ QUrl passUrl1("http://user:pass@host/");
+ QUrl passUrl2("http://user:PASS@host/");
+ QVERIFY(!(passUrl1 == passUrl2));
+ QVERIFY(passUrl1 != passUrl2);
+ QVERIFY(!passUrl1.matches(passUrl2, QUrl::None));
+ QVERIFY(passUrl1.matches(passUrl2, QUrl::RemovePassword));
+
+ // RemoveQuery, RemoveFragment
+ QUrl queryFragUrl1("http://host/file?query#fragment");
+ QUrl queryFragUrl2("http://host/file?q2#f2");
+ QUrl queryFragUrl3("http://host/file");
+ QVERIFY(!(queryFragUrl1 == queryFragUrl2));
+ QVERIFY(queryFragUrl1 != queryFragUrl2);
+ QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::None));
+ QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery));
+ QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveFragment));
+ QVERIFY(queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery | QUrl::RemoveFragment));
+ QVERIFY(queryFragUrl1.matches(queryFragUrl3, QUrl::RemoveQuery | QUrl::RemoveFragment));
+ QVERIFY(queryFragUrl3.matches(queryFragUrl1, QUrl::RemoveQuery | QUrl::RemoveFragment));
}
void tst_QUrl::comparison2_data()
@@ -422,18 +500,20 @@ void tst_QUrl::setUrl()
}
{
- QUrl url("http://user:pass@[56::56:56:56:127.0.0.1]:99");
+ QUrl url("http://user%3A:pass%40@[56::56:56:56:127.0.0.1]:99");
QVERIFY(url.isValid());
QCOMPARE(url.scheme(), QString::fromLatin1("http"));
QCOMPARE(url.path(), QString());
QVERIFY(url.encodedQuery().isEmpty());
- QCOMPARE(url.userInfo(), QString::fromLatin1("user:pass"));
+ QCOMPARE(url.userName(), QString::fromLatin1("user:"));
+ QCOMPARE(url.password(), QString::fromLatin1("pass@"));
+ QCOMPARE(url.userInfo(), QString::fromLatin1("user%3A:pass@"));
QVERIFY(url.fragment().isEmpty());
QCOMPARE(url.host(), QString::fromLatin1("56::56:56:56:7f00:1"));
- QCOMPARE(url.authority(), QString::fromLatin1("user:pass@[56::56:56:56:7f00:1]:99"));
+ QCOMPARE(url.authority(), QString::fromLatin1("user%3A:pass%40@[56::56:56:56:7f00:1]:99"));
QCOMPARE(url.port(), 99);
- QCOMPARE(url.url(), QString::fromLatin1("http://user:pass@[56::56:56:56:7f00:1]:99"));
- QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://user@[56::56:56:56:7f00:1]:99"));
+ QCOMPARE(url.url(), QString::fromLatin1("http://user%3A:pass%40@[56::56:56:56:7f00:1]:99"));
+ QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://user%3A@[56::56:56:56:7f00:1]:99"));
}
{
@@ -611,8 +691,8 @@ void tst_QUrl::setUrl()
QUrl charles;
charles.setPath("/home/charles/foo%20moo");
- QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo moo"));
- QCOMPARE(charles.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%20moo"));
+ QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo%20moo"));
+ QCOMPARE(charles.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%2520moo"));
QUrl charles2("file:/home/charles/foo%20moo");
QCOMPARE(charles2.path(), QString::fromLatin1("/home/charles/foo moo"));
@@ -686,7 +766,7 @@ void tst_QUrl::setUrl()
QCOMPARE(url.scheme(), QString("data"));
QCOMPARE(url.host(), QString());
QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';"));
- QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20=%20'five%5Cu0027s';");
+ QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20%3D%20'five%5Cu0027s'%3B");
}
{
@@ -946,8 +1026,12 @@ void tst_QUrl::toString()
QFETCH(uint, options);
QFETCH(QString, string);
+ QUrl::FormattingOptions opt(options);
+
QUrl url(urlString);
- QCOMPARE(url.toString(QUrl::FormattingOptions(options)), string);
+ QCOMPARE(url.toString(opt), string);
+
+ QCOMPARE(url.adjusted(opt).toString(), string);
}
void tst_QUrl::toAndFromStringList_data()
@@ -1135,11 +1219,11 @@ void tst_QUrl::fromLocalFile_data()
QTest::newRow("data7") << QString::fromLatin1("/Mambo <#5>.mp3") << QString::fromLatin1("file:///Mambo <%235>.mp3")
<< QString::fromLatin1("/Mambo <#5>.mp3");
QTest::newRow("data8") << QString::fromLatin1("/a%.txt") << QString::fromLatin1("file:///a%25.txt")
- << QString::fromLatin1("/a%25.txt");
+ << QString::fromLatin1("/a%.txt");
QTest::newRow("data9") << QString::fromLatin1("/a%25.txt") << QString::fromLatin1("file:///a%2525.txt")
- << QString::fromLatin1("/a%2525.txt");
+ << QString::fromLatin1("/a%25.txt");
QTest::newRow("data10") << QString::fromLatin1("/%80.txt") << QString::fromLatin1("file:///%2580.txt")
- << QString::fromLatin1("/%2580.txt");
+ << QString::fromLatin1("/%80.txt");
}
void tst_QUrl::fromLocalFile()
@@ -1154,6 +1238,16 @@ void tst_QUrl::fromLocalFile()
QCOMPARE(url.path(), thePath);
}
+void tst_QUrl::macTypes()
+{
+#ifndef Q_OS_MAC
+ QSKIP("This is a Mac-only test");
+#else
+ extern void tst_QUrl_mactypes(); // in tst_qurl_mac.mm
+ void tst_QUrl_mactypes();
+#endif
+}
+
void tst_QUrl::compat_legacy()
{
{
@@ -1498,17 +1592,17 @@ void tst_QUrl::relative()
void tst_QUrl::percentEncoding_data()
{
+ // This test is limited. It's superseded by componentEncodings below
QTest::addColumn<QString>("original");
QTest::addColumn<QByteArray>("encoded");
QTest::newRow("test_01") << QString::fromLatin1("sdfsdf") << QByteArray("sdfsdf");
QTest::newRow("test_02") << QString::fromUtf8("æss") << QByteArray("%C3%A6ss");
- // not unreserved or reserved
- QTest::newRow("test_03") << QString::fromLatin1("{}") << QByteArray("%7B%7D");
}
void tst_QUrl::percentEncoding()
{
+ // This test is limited. It's superseded by componentEncodings below
QFETCH(QString, original);
QFETCH(QByteArray, encoded);
@@ -1583,21 +1677,83 @@ void tst_QUrl::symmetry()
{
QString urlString = QString::fromLatin1("http://desktop:33326/upnp/{32f525a6-6f31-426e-91ca-01c2e6c2c57e}");
+ QString encodedUrlString = QString("http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D");
QUrl urlPreviewList(urlString);
- QCOMPARE(urlPreviewList.toString(), urlString);
+ QCOMPARE(urlPreviewList.toString(), encodedUrlString);
QByteArray b = urlPreviewList.toEncoded();
- QCOMPARE(b.constData(), "http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D");
- QCOMPARE(QUrl::fromEncoded(b).toString(), urlString);
- QCOMPARE(QUrl(b).toString(), urlString);
+ QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData());
+ QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString);
+ QCOMPARE(QUrl(b).toString(), encodedUrlString);
}
{
QString urlString = QString::fromLatin1("http://desktop:53423/deviceDescription?uuid={7977c17b-00bf-4af9-894e-fed28573c3a9}");
+ QString encodedUrlString = QString("http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D");
QUrl urlPreviewList(urlString);
- QCOMPARE(urlPreviewList.toString(), urlString);
+ QCOMPARE(urlPreviewList.toString(), encodedUrlString);
QByteArray b = urlPreviewList.toEncoded();
- QCOMPARE(b.constData(), "http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D");
- QCOMPARE(QUrl::fromEncoded(b).toString(), urlString);
- QCOMPARE(QUrl(b).toString(), urlString);
+ QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData());
+ QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString);
+ QCOMPARE(QUrl(b).toString(), encodedUrlString);
+ }
+}
+
+void tst_QUrl::ipvfuture_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<bool>("isValid");
+ QTest::addColumn<QString>("output");
+
+ // No one uses IPvFuture yet, so we have no clue what it might contain
+ // We're just testing that it can hold what the RFC says it should hold:
+ // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+ QTest::newRow("missing-version-dot") << "x://[v]" << false;
+ QTest::newRow("missing-version") << "x://[v.]" << false;
+ QTest::newRow("missing-version-2") << "x://[v.1234]" << false;
+ QTest::newRow("missing-dot") << "x://[v7]" << false;
+ QTest::newRow("missing-dot-2") << "x://[v71234]" << false;
+ QTest::newRow("missing-data") << "x://[v7.]" << false;
+ QTest::newRow("non-hex-version") << "x://[vz.1234]" << false;
+
+ QTest::newRow("digit-ver") << "x://[v7.1]" << true << "x://[v7.1]";
+ QTest::newRow("lowercase-hex-ver") << "x://[va.1]" << true << "x://[vA.1]";
+ QTest::newRow("lowercase-hex-ver") << "x://[vA.1]" << true << "x://[vA.1]";
+
+ QTest::newRow("data-digits") << "x://[v7.1234]" << true << "x://[v7.1234]";
+ QTest::newRow("data-unreserved") << "x://[v7.hello~-WORLD_.com]" << true << "x://[v7.hello~-WORLD_.com]";
+ QTest::newRow("data-sub-delims-colon") << "x://[v7.!$&'()*+,;=:]" << true << "x://[v7.!$&'()*+,;=:]";
+
+ // we're using the tolerant parser
+ QTest::newRow("data-encoded-digits") << "x://[v7.%31%32%33%34]" << true << "x://[v7.1234]";
+ QTest::newRow("data-encoded-unreserved") << "x://[v7.%7E%2D%54%5f%2E]" << true << "x://[v7.~-T_.]";
+ QTest::newRow("data-encoded-sub-delims-colon") << "x://[v7.%21%24%26%27%28%29%2A%2B%2C%3B%3D%3A]" << true << "x://[v7.!$&'()*+,;=:]";
+
+ // should we test "[%76%37%2ex]" -> "[v7.x]" ?
+
+ QTest::newRow("data-invalid-space") << "x://[v7.%20]" << false;
+ QTest::newRow("data-invalid-control") << "x://[v7.\x7f]" << false;
+ QTest::newRow("data-invalid-other-1") << "x://[v7.{1234}]" << false;
+ QTest::newRow("data-invalid-other-2") << "x://[v7.<hello>]" << false;
+ QTest::newRow("data-invalid-unicode") << "x://[v7.æøå]" << false;
+ QTest::newRow("data-invalid-percent") << "x://[v7.%]" << false;
+ QTest::newRow("data-invalid-percent-percent") << "x://[v7.%25]" << false;
+}
+
+void tst_QUrl::ipvfuture()
+{
+ QFETCH(QString, input);
+ QFETCH(bool, isValid);
+
+ QUrl url(input);
+ if (isValid) {
+ QVERIFY2(url.isValid(), qPrintable(url.errorString()));
+
+ QFETCH(QString, output);
+ QCOMPARE(url.toString(), output);
+
+ QUrl url2(output);
+ QCOMPARE(url2, url);
+ } else {
+ QVERIFY(!url.isValid());
}
}
@@ -1641,6 +1797,9 @@ void tst_QUrl::ipv6_data()
QTest::newRow("case :,") << QString::fromLatin1("//[:,]") << false << "";
QTest::newRow("case ::bla") << QString::fromLatin1("//[::bla]") << false << "";
QTest::newRow("case v4-mapped") << "//[0:0:0:0:0:ffff:7f00:1]" << true << "//[::ffff:127.0.0.1]";
+
+ QTest::newRow("encoded-digit") << "//[::%31]" << true << "//[::1]";
+ QTest::newRow("encoded-colon") << "//[%3A%3A]" << true << "//[::]";
}
void tst_QUrl::ipv6()
@@ -1932,9 +2091,14 @@ void tst_QUrl::strictParser_data()
QTest::newRow("invalid-regname") << "http://bad<hostname>" << "Invalid hostname (contains invalid characters)";
QTest::newRow("invalid-regname-2") << "http://b%61d" << "Invalid hostname (contains invalid characters)";
QTest::newRow("invalid-ipv6") << "http://[:::]" << "Invalid IPv6 address";
+ QTest::newRow("invalid-ipv6-char1") << "http://[::g]" << "Invalid IPv6 address (character 'g' not permitted)";
+ QTest::newRow("invalid-ipv6-char2") << "http://[z::]" << "Invalid IPv6 address (character 'z' not permitted)";
QTest::newRow("invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address";
QTest::newRow("invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address";
QTest::newRow("invalid-ipvfuture-3") << "http://[v789]" << "Invalid IPvFuture address";
+ QTest::newRow("invalid-ipvfuture-char1") << "http://[v7.^]" << "Invalid IPvFuture address";
+ QTest::newRow("invalid-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address";
+ QTest::newRow("invalid-encoded-ipvfuture") << "x://[v7.%7E%2D%54%5f%2E]" << "Invalid IPvFuture address";
QTest::newRow("unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname";
// invalid hostnames happen in TolerantMode too
@@ -2035,35 +2199,22 @@ void tst_QUrl::tolerantParser()
url.setUrl("http://foo.bar/[image][1].jpg");
QVERIFY(url.isValid());
QVERIFY(!url.toString().isEmpty());
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
- QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg"));
+ QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg"));
QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg"));
- url.setUrl("[].jpg");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg"));
- QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg"));
- QCOMPARE(url.toString(), QString("[].jpg"));
-
- url.setUrl("/some/[path]/[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D"));
- QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D"));
- QCOMPARE(url.toString(), QString("/some/[path]/[]"));
+ url.setUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg");
+ QVERIFY(url.isValid());
+ QVERIFY(!url.toString().isEmpty());
+ QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
url.setUrl("//[::56:56:56:56:56:56:56]");
QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]"));
QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]"));
QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]"));
- url.setUrl("//[::56:56:56:56:56:56:56]#[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D"));
- QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D"));
- QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]"));
-
- url.setUrl("//[::56:56:56:56:56:56:56]?[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]"));
- QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]"));
- QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]"));
-
// invoke the tolerant parser's error correction
url.setUrl("%hello.com/f%");
QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%25hello.com/f%25"));
@@ -2076,38 +2227,24 @@ void tst_QUrl::tolerantParser()
url.setEncodedUrl("http://foo.bar/[image][1].jpg");
QVERIFY(url.isValid());
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
- QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg"));
+ QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg"));
QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg"));
- url.setEncodedUrl("[].jpg");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg"));
- QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg"));
- QCOMPARE(url.toString(), QString("[].jpg"));
-
- url.setEncodedUrl("/some/[path]/[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D"));
- QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D"));
- QCOMPARE(url.toString(), QString("/some/[path]/[]"));
+ url.setEncodedUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg");
+ QVERIFY(url.isValid());
+ QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
+ QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
url.setEncodedUrl("//[::56:56:56:56:56:56:56]");
QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]"));
QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]"));
- url.setEncodedUrl("//[::56:56:56:56:56:56:56]#[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D"));
- QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D"));
- QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]"));
-
- url.setEncodedUrl("//[::56:56:56:56:56:56:56]?[]");
- QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]"));
- QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]"));
- QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]"));
-
url.setEncodedUrl("data:text/css,div%20{%20border-right:%20solid;%20}");
QCOMPARE(url.toString(QUrl::FullyEncoded), QString("data:text/css,div%20%7B%20border-right:%20solid;%20%7D"));
QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D"));
- QCOMPARE(url.toString(), QString("data:text/css,div { border-right: solid; }"));
+ QCOMPARE(url.toString(), QString("data:text/css,div %7B border-right: solid; %7D"));
}
{
@@ -2386,7 +2523,7 @@ void tst_QUrl::setEncodedFragment_data()
QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc");
QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new");
QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c");
- QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a#b");
+ QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a%23b"); // toString uses "a#b"
QTest::newRow("unicode") << BA("http://www.kde.org") << BA("\xc3\xa9") << BA("http://www.kde.org#%C3%A9");
QTest::newRow("binary") << BA("http://www.kde.org") << BA("\x00\xc0\x80", 3) << BA("http://www.kde.org#%00%C0%80");
}
@@ -2408,8 +2545,9 @@ void tst_QUrl::setEncodedFragment()
void tst_QUrl::fromEncoded()
{
QUrl qurl2 = QUrl::fromEncoded("print:/specials/Print%20To%20File%20(PDF%252FAcrobat)", QUrl::TolerantMode);
- QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%252FAcrobat)"));
- QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%252FAcrobat)"));
+ QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%2FAcrobat)"));
+ QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)"));
+ QCOMPARE(qurl2.fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)"));
QCOMPARE(qurl2.toEncoded().constData(), "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)");
QUrl qurl = QUrl::fromEncoded("http://\303\244.de");
@@ -2427,23 +2565,37 @@ void tst_QUrl::fromEncoded()
void tst_QUrl::stripTrailingSlash_data()
{
QTest::addColumn<QString>("url");
- QTest::addColumn<QString>("expected");
+ QTest::addColumn<QString>("expectedStrip"); // toString(Strip)
+ QTest::addColumn<QString>("expectedDir"); // toString(RemoveFilename)
+ QTest::addColumn<QString>("expectedDirStrip"); // toString(RemoveFilename|Strip)
- QTest::newRow("ftp no slash") << "ftp://ftp.de.kde.org/dir" << "ftp://ftp.de.kde.org/dir";
- QTest::newRow("ftp slash") << "ftp://ftp.de.kde.org/dir/" << "ftp://ftp.de.kde.org/dir";
- QTest::newRow("file slash") << "file:///dir/" << "file:///dir";
- QTest::newRow("file no slash") << "file:///dir/" << "file:///dir";
- QTest::newRow("file root") << "file:///" << "file:///";
- QTest::newRow("no path") << "remote://" << "remote://";
+ QTest::newRow("subdir no slash") << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir";
+ QTest::newRow("ftp no slash") << "ftp://kde.org/dir" << "ftp://kde.org/dir" << "ftp://kde.org/" << "ftp://kde.org/";
+ QTest::newRow("ftp slash") << "ftp://kde.org/dir/" << "ftp://kde.org/dir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir";
+ QTest::newRow("ftp_two_slashes") << "ftp://kde.org/dir//" << "ftp://kde.org/dir" << "ftp://kde.org/dir//" << "ftp://kde.org/dir";
+ QTest::newRow("file slash") << "file:///dir/" << "file:///dir" << "file:///dir/" << "file:///dir";
+ QTest::newRow("file no slash") << "file:///dir" << "file:///dir" << "file:///" << "file:///";
+ QTest::newRow("file root") << "file:///" << "file:///" << "file:///" << "file:///";
+ QTest::newRow("file_root_manyslashes") << "file://///" << "file:///" << "file://///" << "file:///";
+ QTest::newRow("no path") << "remote://" << "remote://" << "remote://" << "remote://";
}
void tst_QUrl::stripTrailingSlash()
{
QFETCH(QString, url);
- QFETCH(QString, expected);
+ QFETCH(QString, expectedStrip);
+ QFETCH(QString, expectedDir);
+ QFETCH(QString, expectedDirStrip);
QUrl u(url);
- QCOMPARE(u.toString(QUrl::StripTrailingSlash), expected);
+ QCOMPARE(u.toString(QUrl::StripTrailingSlash), expectedStrip);
+ QCOMPARE(u.toString(QUrl::RemoveFilename), expectedDir);
+ QCOMPARE(u.toString(QUrl::RemoveFilename | QUrl::StripTrailingSlash), expectedDirStrip);
+
+ // Same thing, using QUrl::adjusted()
+ QCOMPARE(u.adjusted(QUrl::StripTrailingSlash).toString(), expectedStrip);
+ QCOMPARE(u.adjusted(QUrl::RemoveFilename).toString(), expectedDir);
+ QCOMPARE(u.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toString(), expectedDirStrip);
}
void tst_QUrl::hosts_data()
@@ -2503,6 +2655,29 @@ void tst_QUrl::hosts()
QTEST(QUrl(url).host(), "host");
}
+void tst_QUrl::hostFlags_data()
+{
+ QTest::addColumn<QString>("urlStr");
+ QTest::addColumn<QUrl::FormattingOptions>("options");
+ QTest::addColumn<QString>("expectedHost");
+
+ QString swedish = QString::fromUtf8("http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl");
+ QTest::newRow("se_fullydecoded") << swedish << QUrl::FormattingOptions(QUrl::FullyDecoded) << QString::fromUtf8("www.räksmörgås.se");
+ QTest::newRow("se_fullyencoded") << swedish << QUrl::FormattingOptions(QUrl::FullyEncoded) << QString::fromUtf8("www.xn--rksmrgs-5wao1o.se");
+ QTest::newRow("se_prettydecoded") << swedish << QUrl::FormattingOptions(QUrl::PrettyDecoded) << QString::fromUtf8("www.räksmörgås.se");
+ QTest::newRow("se_encodespaces") << swedish << QUrl::FormattingOptions(QUrl::EncodeSpaces) << QString::fromUtf8("www.räksmörgås.se");
+}
+
+void tst_QUrl::hostFlags()
+{
+ QFETCH(QString, urlStr);
+ QFETCH(QUrl::FormattingOptions, options);
+ QFETCH(QString, expectedHost);
+
+ QUrl url(urlStr);
+ QCOMPARE(url.host(options), expectedHost);
+}
+
void tst_QUrl::setPort()
{
{
@@ -2729,6 +2904,43 @@ void tst_QUrl::fromUserInput()
QCOMPARE(url, guessUrlFromString);
}
+void tst_QUrl::fileName_data()
+{
+ QTest::addColumn<QString>("urlStr");
+ QTest::addColumn<QString>("expectedDirPath");
+ QTest::addColumn<QString>("expectedPrettyDecodedFileName");
+ QTest::addColumn<QString>("expectedFullyDecodedFileName");
+
+ QTest::newRow("fromDocu") << "http://qt-project.org/support/file.html"
+ << "/support/" << "file.html" << "file.html";
+ QTest::newRow("absoluteFile") << "file:///temp/tmp.txt"
+ << "/temp/" << "tmp.txt" << "tmp.txt";
+ QTest::newRow("absoluteDir") << "file:///temp/"
+ << "/temp/" << QString() << QString();
+ QTest::newRow("absoluteInRoot") << "file:///temp"
+ << "/" << "temp" << "temp";
+ QTest::newRow("relative") << "temp/tmp.txt"
+ << "temp/" << "tmp.txt" << "tmp.txt";
+ QTest::newRow("relativeNoSlash") << "tmp.txt"
+ << QString() << "tmp.txt" << "tmp.txt";
+ QTest::newRow("encoded") << "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)"
+ << "/specials/" << "Print To File (PDF%252FAcrobat)" << "Print To File (PDF%2FAcrobat)";
+}
+
+void tst_QUrl::fileName()
+{
+ QFETCH(QString, urlStr);
+ QFETCH(QString, expectedDirPath);
+ QFETCH(QString, expectedPrettyDecodedFileName);
+ QFETCH(QString, expectedFullyDecodedFileName);
+
+ QUrl url(urlStr);
+ QVERIFY(url.isValid());
+ QCOMPARE(url.adjusted(QUrl::RemoveFilename).path(), expectedDirPath);
+ QCOMPARE(url.fileName(QUrl::PrettyDecoded), expectedPrettyDecodedFileName);
+ QCOMPARE(url.fileName(QUrl::FullyDecoded), expectedFullyDecodedFileName);
+}
+
// This is a regression test for a previously fixed bug where isEmpty didn't
// work for an encoded URL that was yet to be decoded. The test checks that
// isEmpty works for an encoded URL both after and before decoding.
@@ -2866,7 +3078,8 @@ void tst_QUrl::effectiveTLDs()
{
QFETCH(QUrl, domain);
QFETCH(QString, TLD);
- QCOMPARE(domain.topLevelDomain(), TLD);
+ QCOMPARE(domain.topLevelDomain(QUrl::PrettyDecoded), TLD);
+ QCOMPARE(domain.topLevelDomain(QUrl::FullyDecoded), TLD);
}
void tst_QUrl::lowercasesScheme()
@@ -2950,19 +3163,25 @@ void tst_QUrl::componentEncodings_data()
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
// / "*" / "+" / "," / ";" / "="
- // like the unreserved, these are decoded everywhere
- // don't test in query because they might remain encoded
- QTest::newRow("decoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c#%3b%3d")
+ // these are always left alone
+ QTest::newRow("decoded-subdelims") << QUrl("x://!$&:'()@host/*+,?$=(+)#;=")
<< int(QUrl::FullyEncoded)
<< "!$&" << "'()" << "!$&:'()"
<< "host" << "!$&:'()@host"
- << "/*+," << "" << ";="
- << "x://!$&:'()@host/*+,#;=";
+ << "/*+," << "$=(+)" << ";="
+ << "x://!$&:'()@host/*+,?$=(+)#;=";
+ QTest::newRow("encoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d")
+ << MostDecoded
+ << "%21%24%26" << "%27%28%29" << "%21%24%26:%27%28%29"
+ << "host" << "%21%24%26:%27%28%29@host"
+ << "/%2A%2B%2C" << "%26=%26&%3D=%3D" << "%3B%3D"
+ << "x://%21%24%26:%27%28%29@host/%2A%2B%2C?%26=%26&%3D=%3D#%3B%3D";
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
// these are the separators between fields
- // they must appear encoded in certain positions, no exceptions
- // in other positions, they can appear decoded, so they always do
+ // they must appear encoded in certain positions in the full URL, no exceptions
+ // when in those positions, they appear decoded in the isolated parts
+ // in other positions and the other delimiters are always left untransformed
// 1) test the delimiters that must appear encoded
// (if they were decoded, they'd would change the URL parsing)
QTest::newRow("encoded-gendelims-changing") << QUrl("x://%5b%3a%2f%3f%23%40%5d:%5b%2f%3f%23%40%5d@host/%2f%3f%23?%23")
@@ -2972,32 +3191,21 @@ void tst_QUrl::componentEncodings_data()
<< "/%2F?#" << "#" << ""
<< "x://%5B%3A%2F%3F%23%40%5D:%5B%2F%3F%23%40%5D@host/%2F%3F%23?%23";
- // 2) test the delimiters that may appear decoded and would not change the meaning
- // and test that %2f is *not* decoded to a slash in the path
- // don't test the query because in this mode it doesn't transform anything
- QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://:%3a@host/%2f%3a%40#%23%3a%2f%3f%40")
+ // 2) test that the other delimiters remain decoded
+ QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?#:/?@[]")
<< int(QUrl::FullyEncoded)
<< "" << ":" << "::"
<< "host" << "::@host"
- << "/%2F:@" << "" << "#:/?@"
- << "x://::@host/%2F:@##:/?@";
-
- // 3) test "[" and "]". Even though they are not ambiguous in the path, query or fragment
- // the RFC does not allow them to appear there decoded. QUrl adheres strictly in FullyEncoded mode
- QTest::newRow("encoded-square-brackets") << QUrl("x:/[]#[]")
- << int(QUrl::FullyEncoded)
- << "" << "" << ""
- << "" << ""
- << "/%5B%5D" << "" << "%5B%5D"
- << "x:/%5B%5D#%5B%5D";
-
- // 4) like above, but now decode them, which is allowed
- QTest::newRow("decoded-square-brackets") << QUrl("x:/%5B%5D#%5B%5D")
- << MostDecoded
- << "" << "" << ""
- << "" << ""
- << "/[]" << "" << "[]"
- << "x:/[]#[]";
+ << "/:@/[]" << ":/?@[]?" << ":/?@[]"
+ << "x://::@host/:@/[]?:/?@[]?#:/?@[]";
+
+ // 3) and test that the same encoded sequences remain encoded
+ QTest::newRow("encoded-gendelims-unchanging") << QUrl("x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D")
+ << MostDecoded
+ << "" << "%3A" << ":%3A"
+ << "host" << ":%3A@host"
+ << "/%3A%40%5B%5D" << "%3A%2F%3F%40%5B%5D" << "%23%3A%2F%3F%40%5B%5D"
+ << "x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D";
// test the query
// since QUrl doesn't know what chars the user wants to use for the pair and value delimiters,
@@ -3051,23 +3259,13 @@ void tst_QUrl::componentEncodings_data()
<< QString::fromUtf8("é ")
<< QString::fromUtf8("x:// é:é @smørbrød.example.no/é ? é#é ");
- // the pretty form re-encodes the subdelims (except in the query, where they are left alone)
- QTest::newRow("pretty-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d")
- << int(QUrl::PrettyDecoded)
- << "!$&" << "'()" << "!$&:'()"
- << "host" << "!$&:'()@host"
- << "/*+," << "%26=%26&%3D=%3D" << ";="
- << "x://!$&:'()@host/*+,?%26=%26&%3D=%3D#;=";
-
- // the pretty form decodes all unambiguous gen-delims
- // (except in query, where they are left alone)
- QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%5d:%5b%3a%40%2f%5d@host"
- "/%3a%40%5b%3f%23%5d?[?%3f%23]%5b:%3a@%40%5d#%23")
+ // the pretty form decodes all unambiguous gen-delims in the individual parts
+ QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%3f%23%5d:%5b%40%2f%3f%23%5d@host/%3f%23?%23")
<< int(QUrl::PrettyDecoded)
- << "[:@/]" << "[:@/]" << "[%3A@/]:[:@/]"
- << "host" << "%5B%3A%40/%5D:%5B:%40/%5D@host"
- << "/:@[?#]" << "[?%3F#]%5B:%3A@%40%5D" << "#"
- << "x://%5B%3A%40%2F%5D:%5B:%40%2F%5D@host/:@[%3F%23]?[?%3F%23]%5B:%3A@%40%5D##";
+ << "[:@/?#]" << "[@/?#]" << "[%3A@/?#]:[@/?#]"
+ << "host" << "%5B%3A%40/?#%5D:%5B%40/?#%5D@host"
+ << "/?#" << "#" << ""
+ << "x://%5B%3A%40%2F%3F%23%5D:%5B%40%2F%3F%23%5D@host/%3F%23?%23";
// the pretty form keeps the other characters decoded everywhere
// except when rebuilding the full URL, when we only allow "{}" to remain decoded
@@ -3076,8 +3274,8 @@ void tst_QUrl::componentEncodings_data()
<< "\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}:\"<>^\\{|}"
<< "host" << "\"<>^\\{|}:\"<>^\\{|}@host"
<< "/\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}"
- << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C{%7C}"
- "?%22%3C%3E%5E%5C{%7C}#%22%3C%3E%5E%5C%7B%7C%7D";
+ << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C%7B%7C%7D"
+ "?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D";
}
void tst_QUrl::componentEncodings()
@@ -3181,6 +3379,17 @@ void tst_QUrl::setComponents_data()
QTest::newRow("path-empty") << QUrl("http://example.com/path")
<< int(Path) << "" << Tolerant << true
<< PrettyDecoded << "" << "http://example.com";
+ // If the %3A gets decoded to ":", the URL becomes invalid;
+ // see test path-invalid-1 below
+ QTest::newRow("path-%3A-before-slash") << QUrl()
+ << int(Path) << "c%3A/" << Tolerant << true
+ << PrettyDecoded << "c%3A/" << "c%3A/";
+ QTest::newRow("path-doubleslash") << QUrl("trash:/")
+ << int(Path) << "//path" << Tolerant << true
+ << PrettyDecoded << "/path" << "trash:/path";
+ QTest::newRow("path-withdotdot") << QUrl("file:///tmp")
+ << int(Path) << "//tmp/..///root/." << Tolerant << true
+ << PrettyDecoded << "/root" << "file:///root";
// the other fields can be present and be empty
// that is, their delimiters would be present, but there would be nothing to one side
@@ -3346,9 +3555,6 @@ void tst_QUrl::setComponents_data()
QTest::newRow("invalid-scheme-encode") << QUrl("http://example.com")
<< int(Scheme) << "http%61" << Decoded << false
<< PrettyDecoded << "" << "";
- QTest::newRow("userinfo-encode") << QUrl("http://example.com")
- << int(UserInfo) << "h%61llo:world@" << Decoded << true
- << PrettyDecoded << "h%2561llo:world@" << "http://h%2561llo:world%40@example.com";
QTest::newRow("username-encode") << QUrl("http://example.com")
<< int(UserName) << "h%61llo:world" << Decoded << true
<< PrettyDecoded << "h%2561llo:world" << "http://h%2561llo%3Aworld@example.com";
@@ -3359,9 +3565,6 @@ void tst_QUrl::setComponents_data()
QTest::newRow("invalid-host-encode") << QUrl("http://example.com")
<< int(Host) << "ex%61mple.com" << Decoded << false
<< PrettyDecoded << "" << "";
- QTest::newRow("invalid-authority-encode") << QUrl("http://example.com")
- << int(Authority) << "ex%61mple.com" << Decoded << false
- << PrettyDecoded << "" << "";
QTest::newRow("path-encode") << QUrl("http://example.com/foo")
<< int(Path) << "/bar%23" << Decoded << true
<< PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523";
@@ -3371,11 +3574,7 @@ void tst_QUrl::setComponents_data()
QTest::newRow("fragment-encode") << QUrl("http://example.com/foo#z")
<< int(Fragment) << "bar%23" << Decoded << true
<< PrettyDecoded << "bar%2523" << "http://example.com/foo#bar%2523";
- // force decoding; note how the userinfo becomes ambiguous
- QTest::newRow("userinfo-decode") << QUrl("http://example.com")
- << int(UserInfo) << "hello%3Aworld:}}>b9o%25kR(" << Tolerant << true
- << FullyDecoded << "hello:world:}}>b9o%kR("
- << "http://hello%3Aworld:%7D%7D%3Eb9o%25kR(@example.com";
+ // force decoding
QTest::newRow("username-decode") << QUrl("http://example.com")
<< int(UserName) << "hello%3Aworld%25" << Tolerant << true
<< FullyDecoded << "hello:world%" << "http://hello%3Aworld%25@example.com";
@@ -3460,6 +3659,8 @@ void tst_QUrl::setComponents()
if (isValid) {
QFETCH(QString, toString);
QCOMPARE(copy.toString(), toString);
+ // Check round-tripping
+ QCOMPARE(QUrl(copy.toString()).toString(), toString);
} else {
QVERIFY(copy.toString().isEmpty());
}
diff --git a/tests/auto/corelib/io/qurl/tst_qurl_mac.mm b/tests/auto/corelib/io/qurl/tst_qurl_mac.mm
new file mode 100644
index 0000000000..90b01a261b
--- /dev/null
+++ b/tests/auto/corelib/io/qurl/tst_qurl_mac.mm
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+void tst_QUrl_macTypes()
+{
+ {
+ QUrl qtUrl("example.com");
+ const CFURLRef cfUrl = qtUrl.toCFURL();
+ QCOMPARE(QUrl::fromCFURL(cfUrl), qtUrl);
+ qtUrl.setUrl("www.example.com");
+ QVERIFY(QUrl::fromCFURL(cfUrl) != qtUrl);
+ }
+ {
+ QUrl qtUrl("example.com");
+ const NSURL *nsUrl = qtUrl.toNSURL();
+ QCOMPARE(QUrl::fromNSURL(nsUrl), qtUrl);
+ qtUrl.setUrl("www.example.com");
+ QVERIFY(QUrl::fromNSURL(nsUrl) != qtUrl);
+ }
+}
diff --git a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp
index 4b74dd7906..75b17df759 100644
--- a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp
+++ b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp
@@ -825,12 +825,20 @@ void tst_QUrlInternal::correctEncodedMistakes()
QFETCH(QString, expected);
// prepend some data to be sure that it remains there
- QString output = QTest::currentDataTag();
- expected.prepend(output);
+ QString dataTag = QTest::currentDataTag();
+ QString output = dataTag;
if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), 0))
output += input;
- QCOMPARE(output, expected);
+ QCOMPARE(output, dataTag + expected);
+
+ // now try the full decode mode
+ output = dataTag;
+ QString expected2 = QUrl::fromPercentEncoding(expected.toLatin1());
+
+ if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyDecoded))
+ output += input;
+ QCOMPARE(output, dataTag + expected2);
}
static void addUtf8Data(const char *name, const char *data)
@@ -1028,6 +1036,15 @@ void tst_QUrlInternal::encodingRecodeInvalidUtf8()
if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded))
output += input;
QCOMPARE(output, QTest::currentDataTag() + input);
+
+ // verify for security reasons that all bad UTF-8 data got replaced by QChar::ReplacementCharacter
+ output = QTest::currentDataTag();
+ if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded))
+ output += input;
+ for (int i = strlen(QTest::currentDataTag()); i < output.length(); ++i) {
+ QVERIFY2(output.at(i).unicode() < 0x80 || output.at(i) == QChar::ReplacementCharacter,
+ qPrintable(QString("Character at i == %1 was U+%2").arg(i).arg(output.at(i).unicode(), 4, 16, QLatin1Char('0'))));
+ }
}
void tst_QUrlInternal::recodeByteArray_data()
diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp
index 94e6e1129e..9dbd6414ad 100644
--- a/tests/auto/corelib/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/json/tst_qtjson.cpp
@@ -45,6 +45,7 @@
#include "qjsonobject.h"
#include "qjsonvalue.h"
#include "qjsondocument.h"
+#include <limits>
#define INVALID_UNICODE "\357\277\277" // "\uffff"
#define UNICODE_DJE "\320\202" // Character from the Serbian Cyrillic alphabet
@@ -97,6 +98,8 @@ private Q_SLOTS:
void toVariantList();
void toJson();
+ void toJsonSillyNumericValues();
+ void toJsonLargeNumericValues();
void fromJson();
void fromJsonErrors();
void fromBinary();
@@ -446,13 +449,13 @@ void tst_QtJson::testObjectSimple()
void tst_QtJson::testObjectSmallKeys()
{
QJsonObject data1;
- data1.insert(QStringLiteral("1"), 123);
+ data1.insert(QStringLiteral("1"), 123.);
QVERIFY(data1.contains(QStringLiteral("1")));
QCOMPARE(data1.value(QStringLiteral("1")).toDouble(), (double)123);
- data1.insert(QStringLiteral("12"), 133);
+ data1.insert(QStringLiteral("12"), 133.);
QCOMPARE(data1.value(QStringLiteral("12")).toDouble(), (double)133);
QVERIFY(data1.contains(QStringLiteral("12")));
- data1.insert(QStringLiteral("123"), 323);
+ data1.insert(QStringLiteral("123"), 323.);
QCOMPARE(data1.value(QStringLiteral("12")).toDouble(), (double)133);
QVERIFY(data1.contains(QStringLiteral("123")));
QCOMPARE(data1.value(QStringLiteral("123")).type(), QJsonValue::Double);
@@ -667,11 +670,15 @@ void tst_QtJson::testValueRef()
array.append(1.);
array.append(2.);
array.append(3.);
+ array.append(4);
+ array.append(4.1);
array[1] = false;
- QCOMPARE(array.size(), 3);
+ QCOMPARE(array.size(), 5);
QCOMPARE(array.at(0).toDouble(), 1.);
QCOMPARE(array.at(2).toDouble(), 3.);
+ QCOMPARE(array.at(3).toInt(), 4);
+ QCOMPARE(array.at(4).toInt(), 0);
QCOMPARE(array.at(1).type(), QJsonValue::Bool);
QCOMPARE(array.at(1).toBool(), false);
@@ -1201,6 +1208,89 @@ void tst_QtJson::toJson()
}
}
+void tst_QtJson::toJsonSillyNumericValues()
+{
+ QJsonObject object;
+ QJsonArray array;
+ array.append(QJsonValue(std::numeric_limits<double>::infinity())); // encode to: null
+ array.append(QJsonValue(-std::numeric_limits<double>::infinity())); // encode to: null
+ array.append(QJsonValue(std::numeric_limits<double>::quiet_NaN())); // encode to: null
+ object.insert("Array", array);
+
+ QByteArray json = QJsonDocument(object).toJson();
+
+ QByteArray expected =
+ "{\n"
+ " \"Array\": [\n"
+ " null,\n"
+ " null,\n"
+ " null\n"
+ " ]\n"
+ "}\n";
+
+ QCOMPARE(json, expected);
+
+ QJsonDocument doc;
+ doc.setObject(object);
+ json = doc.toJson();
+ QCOMPARE(json, expected);
+}
+
+void tst_QtJson::toJsonLargeNumericValues()
+{
+ QJsonObject object;
+ QJsonArray array;
+ array.append(QJsonValue(1.234567)); // actual precision bug in Qt 5.0.0
+ array.append(QJsonValue(1.7976931348623157e+308)); // JS Number.MAX_VALUE
+ array.append(QJsonValue(5e-324)); // JS Number.MIN_VALUE
+ array.append(QJsonValue(std::numeric_limits<double>::min()));
+ array.append(QJsonValue(std::numeric_limits<double>::max()));
+ array.append(QJsonValue(std::numeric_limits<double>::epsilon()));
+ array.append(QJsonValue(std::numeric_limits<double>::denorm_min()));
+ array.append(QJsonValue(0.0));
+ array.append(QJsonValue(-std::numeric_limits<double>::min()));
+ array.append(QJsonValue(-std::numeric_limits<double>::max()));
+ array.append(QJsonValue(-std::numeric_limits<double>::epsilon()));
+ array.append(QJsonValue(-std::numeric_limits<double>::denorm_min()));
+ array.append(QJsonValue(-0.0));
+ array.append(QJsonValue(9007199254740992LL)); // JS Number max integer
+ array.append(QJsonValue(-9007199254740992LL)); // JS Number min integer
+ object.insert("Array", array);
+
+ QByteArray json = QJsonDocument(object).toJson();
+
+ QByteArray expected =
+ "{\n"
+ " \"Array\": [\n"
+ " 1.234567,\n"
+ " 1.7976931348623157e+308,\n"
+ // ((4.9406564584124654e-324 == 5e-324) == true)
+ // I can only think JavaScript has a special formatter to
+ // emit this value for this IEEE754 bit pattern.
+ " 4.9406564584124654e-324,\n"
+ " 2.2250738585072014e-308,\n"
+ " 1.7976931348623157e+308,\n"
+ " 2.2204460492503131e-16,\n"
+ " 4.9406564584124654e-324,\n"
+ " 0,\n"
+ " -2.2250738585072014e-308,\n"
+ " -1.7976931348623157e+308,\n"
+ " -2.2204460492503131e-16,\n"
+ " -4.9406564584124654e-324,\n"
+ " 0,\n"
+ " 9007199254740992,\n"
+ " -9007199254740992\n"
+ " ]\n"
+ "}\n";
+
+ QCOMPARE(json, expected);
+
+ QJsonDocument doc;
+ doc.setObject(object);
+ json = doc.toJson();
+ QCOMPARE(json, expected);
+}
+
void tst_QtJson::fromJson()
{
{
@@ -2084,6 +2174,16 @@ void tst_QtJson::valueEquals()
QVERIFY(QJsonValue(true) != QJsonValue(QJsonArray()));
QVERIFY(QJsonValue(true) != QJsonValue(QJsonObject()));
+ QVERIFY(QJsonValue(1) == QJsonValue(1));
+ QVERIFY(QJsonValue(1) != QJsonValue(2));
+ QVERIFY(QJsonValue(1) == QJsonValue(1.));
+ QVERIFY(QJsonValue(1) != QJsonValue(1.1));
+ QVERIFY(QJsonValue(1) != QJsonValue(QJsonValue::Undefined));
+ QVERIFY(QJsonValue(1) != QJsonValue());
+ QVERIFY(QJsonValue(1) != QJsonValue(true));
+ QVERIFY(QJsonValue(1) != QJsonValue(QJsonArray()));
+ QVERIFY(QJsonValue(1) != QJsonValue(QJsonObject()));
+
QVERIFY(QJsonValue(1.) == QJsonValue(1.));
QVERIFY(QJsonValue(1.) != QJsonValue(2.));
QVERIFY(QJsonValue(1.) != QJsonValue(QJsonValue::Undefined));
diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
index 1c07425fc7..8ca785836a 100644
--- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
+++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp
@@ -78,6 +78,7 @@ private slots:
/* void registerEventNotifiier(); */ // Not implemented here, see tst_QWinEventNotifier instead
void sendPostedEvents_data();
void sendPostedEvents();
+ void processEventsOnlySendsQueuedEvents();
};
bool tst_QEventDispatcher::event(QEvent *e)
@@ -148,8 +149,7 @@ void tst_QEventDispatcher::registerTimer()
// process events, waiting for the next event... this should only fire the precise timer
receivedEventType = -1;
timerIdFromEvent = -1;
- QVERIFY(eventDispatcher->processEvents(QEventLoop::WaitForMoreEvents));
- QCOMPARE(receivedEventType, int(QEvent::Timer));
+ QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), PreciseTimerInterval * 2);
QCOMPARE(timerIdFromEvent, preciseTimerId);
// now unregister it and make sure it's gone
eventDispatcher->unregisterTimer(preciseTimerId);
@@ -161,8 +161,7 @@ void tst_QEventDispatcher::registerTimer()
// do the same again for the coarse timer
receivedEventType = -1;
timerIdFromEvent = -1;
- QVERIFY(eventDispatcher->processEvents(QEventLoop::WaitForMoreEvents));
- QCOMPARE(receivedEventType, int(QEvent::Timer));
+ QTRY_COMPARE_WITH_TIMEOUT(receivedEventType, int(QEvent::Timer), CoarseTimerInterval * 2);
QCOMPARE(timerIdFromEvent, coarseTimerId);
// now unregister it and make sure it's gone
eventDispatcher->unregisterTimer(coarseTimerId);
@@ -209,5 +208,49 @@ void tst_QEventDispatcher::sendPostedEvents()
}
}
+class ProcessEventsOnlySendsQueuedEvents : public QObject
+{
+ Q_OBJECT
+public:
+ int eventsReceived;
+
+ inline ProcessEventsOnlySendsQueuedEvents() : eventsReceived(0) {}
+
+ bool event(QEvent *event)
+ {
+ ++eventsReceived;
+
+ if (event->type() == QEvent::User)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(QEvent::User + 1)));
+
+ return QObject::event(event);
+ }
+public slots:
+ void timerFired()
+ {
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(QEvent::User + 1)));
+ }
+};
+
+void tst_QEventDispatcher::processEventsOnlySendsQueuedEvents()
+{
+ ProcessEventsOnlySendsQueuedEvents object;
+
+ // Posted events during event processing should be handled on
+ // the next processEvents iteration.
+ QCoreApplication::postEvent(&object, new QEvent(QEvent::User));
+ QCoreApplication::processEvents();
+ QCOMPARE(object.eventsReceived, 1);
+ QCoreApplication::processEvents();
+ QCOMPARE(object.eventsReceived, 2);
+
+ // The same goes for posted events during timer processing
+ QTimer::singleShot(0, &object, SLOT(timerFired()));
+ QCoreApplication::processEvents();
+ QCOMPARE(object.eventsReceived, 3);
+ QCoreApplication::processEvents();
+ QCOMPARE(object.eventsReceived, 4);
+}
+
QTEST_MAIN(tst_QEventDispatcher)
#include "tst_qeventdispatcher.moc"
diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
index df374ffc23..c6d04e64db 100644
--- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp
@@ -195,11 +195,11 @@ protected:
void tst_QEventLoop::processEvents()
{
- QSignalSpy spy1(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()));
- QSignalSpy spy2(QAbstractEventDispatcher::instance(), SIGNAL(awake()));
+ QSignalSpy aboutToBlockSpy(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()));
+ QSignalSpy awakeSpy(QAbstractEventDispatcher::instance(), SIGNAL(awake()));
- QVERIFY(spy1.isValid());
- QVERIFY(spy2.isValid());
+ QVERIFY(aboutToBlockSpy.isValid());
+ QVERIFY(awakeSpy.isValid());
QEventLoop eventLoop;
@@ -208,8 +208,8 @@ void tst_QEventLoop::processEvents()
// process posted events, QEventLoop::processEvents() should return
// true
QVERIFY(eventLoop.processEvents());
- QCOMPARE(spy1.count(), 0);
- QCOMPARE(spy2.count(), 1);
+ QCOMPARE(aboutToBlockSpy.count(), 0);
+ QCOMPARE(awakeSpy.count(), 1);
// allow any session manager to complete its handshake, so that
// there are no pending events left.
@@ -222,28 +222,28 @@ void tst_QEventLoop::processEvents()
// no events to process, QEventLoop::processEvents() should return
// false
- spy1.clear();
- spy2.clear();
+ aboutToBlockSpy.clear();
+ awakeSpy.clear();
QVERIFY(!eventLoop.processEvents());
- QCOMPARE(spy1.count(), 0);
- QCOMPARE(spy2.count(), 1);
+ QCOMPARE(aboutToBlockSpy.count(), 0);
+ QCOMPARE(awakeSpy.count(), 1);
// make sure the test doesn't block forever
int timerId = startTimer(100);
// wait for more events to process, QEventLoop::processEvents()
// should return true
- spy1.clear();
- spy2.clear();
+ aboutToBlockSpy.clear();
+ awakeSpy.clear();
QVERIFY(eventLoop.processEvents(QEventLoop::WaitForMoreEvents));
// Verify that the eventloop has blocked and woken up. Some eventloops
// may block and wake up multiple times.
- QVERIFY(spy1.count() > 0);
- QVERIFY(spy2.count() > 0);
+ QVERIFY(aboutToBlockSpy.count() > 0);
+ QVERIFY(awakeSpy.count() > 0);
// We should get one awake for each aboutToBlock, plus one awake when
// processEvents is entered.
- QVERIFY(spy2.count() >= spy1.count());
+ QVERIFY(awakeSpy.count() >= aboutToBlockSpy.count());
killTimer(timerId);
}
diff --git a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
index 98e90ed805..009b4fadda 100644
--- a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
+++ b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
@@ -205,7 +205,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>())
<< (QList<QByteArray>())
<< (QList<QByteArray>())
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokable")
@@ -241,7 +241,7 @@ void tst_QMetaMethod::method_data()
<< QList<int>()
<< QList<QByteArray>()
<< QList<QByteArray>()
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidSignalInt")
@@ -250,7 +250,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << int(QMetaType::Int))
<< (QList<QByteArray>() << QByteArray("int"))
<< (QList<QByteArray>() << QByteArray("voidSignalIntArg"))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableInt")
@@ -286,7 +286,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << qMetaTypeId<qreal>())
<< (QList<QByteArray>() << QByteArray("qreal"))
<< (QList<QByteArray>() << QByteArray("voidSignalQRealArg"))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableQReal")
@@ -322,7 +322,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << int(QMetaType::QString))
<< (QList<QByteArray>() << QByteArray("QString"))
<< (QList<QByteArray>() << QByteArray("voidSignalQStringArg"))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableQString")
@@ -358,7 +358,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << qMetaTypeId<CustomType>())
<< (QList<QByteArray>() << QByteArray("CustomType"))
<< (QList<QByteArray>() << QByteArray("voidSignalCustomTypeArg"))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableCustomType")
@@ -394,7 +394,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << 0)
<< (QList<QByteArray>() << QByteArray("CustomUnregisteredType"))
<< (QList<QByteArray>() << QByteArray("voidSignalCustomUnregisteredTypeArg"))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableCustomUnregisteredType")
@@ -430,7 +430,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>())
<< (QList<QByteArray>())
<< (QList<QByteArray>())
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("boolInvokable")
@@ -457,7 +457,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>())
<< (QList<QByteArray>())
<< (QList<QByteArray>())
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("qrealInvokable")
@@ -484,7 +484,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>())
<< (QList<QByteArray>())
<< (QList<QByteArray>())
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("qstringInvokable")
@@ -529,7 +529,7 @@ void tst_QMetaMethod::method_data()
"bool,int,uint,qlonglong,qulonglong,double,long,short,char,ulong,ushort,uchar,float)")
<< int(QMetaType::QVariant) << QByteArray("QVariant")
<< parameterTypes << parameterTypeNames << parameterNames
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("qvariantInvokableBoolIntUIntLonglongULonglongDoubleLongShortCharUlongUshortUcharFloat")
@@ -562,7 +562,7 @@ void tst_QMetaMethod::method_data()
<< (QList<int>() << int(QMetaType::Bool) << int(QMetaType::Int))
<< (QList<QByteArray>() << QByteArray("bool") << QByteArray("int"))
<< (QList<QByteArray>() << QByteArray("") << QByteArray(""))
- << QMetaMethod::Protected
+ << QMetaMethod::Public
<< QMetaMethod::Signal;
QTest::newRow("voidInvokableNoParameterNames")
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 137ce56730..8f6bd50cca 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -397,7 +397,7 @@ void tst_QMetaObjectBuilder::signal()
QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int");
QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty());
- QVERIFY(method1.access() == QMetaMethod::Protected);
+ QVERIFY(method1.access() == QMetaMethod::Public);
QCOMPARE(method1.attributes(), 0);
QCOMPARE(method1.index(), 0);
QCOMPARE(builder.methodCount(), 1);
@@ -410,7 +410,7 @@ void tst_QMetaObjectBuilder::signal()
QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString");
QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty());
- QVERIFY(method2.access() == QMetaMethod::Protected);
+ QVERIFY(method2.access() == QMetaMethod::Public);
QCOMPARE(method2.attributes(), 0);
QCOMPARE(method2.index(), 1);
QCOMPARE(builder.methodCount(), 2);
diff --git a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
index 5009fedc4f..23a8e6d23a 100644
--- a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
+++ b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro
@@ -1,6 +1,7 @@
CONFIG += testcase parallel_test
TARGET = tst_qmetatype
QT = core testlib
+INCLUDEPATH += $$PWD/../../../other/qvariant_common
SOURCES = tst_qmetatype.cpp
TESTDATA=./typeFlags.bin
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
index 77ea39da53..47900204e7 100644
--- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
+++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp
@@ -43,6 +43,8 @@
#include <QtCore>
#include <QtTest/QtTest>
+#include "tst_qvariant_common.h"
+
#ifdef Q_OS_LINUX
# include <pthread.h>
#endif
@@ -111,6 +113,11 @@ private slots:
void metaObject();
void constexprMetaTypeIds();
void constRefs();
+ void convertCustomType_data();
+ void convertCustomType();
+ void compareCustomType_data();
+ void compareCustomType();
+ void customDebugStream();
};
struct Foo { int i; };
@@ -1302,15 +1309,20 @@ Q_DECLARE_METATYPE(MyObjectPtr)
void tst_QMetaType::automaticTemplateRegistration()
{
- {
- QList<int> intList;
- intList << 42;
- QVERIFY(QVariant::fromValue(intList).value<QList<int> >().first() == 42);
- QVector<QList<int> > vectorList;
- vectorList << intList;
- QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<int> > >().first().first() == 42);
+#define TEST_SEQUENTIAL_CONTAINER(CONTAINER, VALUE_TYPE) \
+ { \
+ CONTAINER<VALUE_TYPE> innerContainer; \
+ innerContainer.push_back(42); \
+ QVERIFY(*QVariant::fromValue(innerContainer).value<CONTAINER<VALUE_TYPE> >().begin() == 42); \
+ QVector<CONTAINER<VALUE_TYPE> > outerContainer; \
+ outerContainer << innerContainer; \
+ QVERIFY(*QVariant::fromValue(outerContainer).value<QVector<CONTAINER<VALUE_TYPE> > >().first().begin() == 42); \
}
+ TEST_SEQUENTIAL_CONTAINER(QList, int)
+ TEST_SEQUENTIAL_CONTAINER(std::vector, int)
+ TEST_SEQUENTIAL_CONTAINER(std::list, int)
+
{
QList<QByteArray> bytearrayList;
bytearrayList << QByteArray("foo");
@@ -1323,14 +1335,9 @@ void tst_QMetaType::automaticTemplateRegistration()
QCOMPARE(::qMetaTypeId<QVariantList>(), (int)QMetaType::QVariantList);
QCOMPARE(::qMetaTypeId<QList<QVariant> >(), (int)QMetaType::QVariantList);
- {
- QList<QVariant> variantList;
- variantList << 42;
- QVERIFY(QVariant::fromValue(variantList).value<QList<QVariant> >().first() == 42);
- QVector<QList<QVariant> > vectorList;
- vectorList << variantList;
- QVERIFY(QVariant::fromValue(vectorList).value<QVector<QList<QVariant> > >().first().first() == 42);
- }
+ TEST_SEQUENTIAL_CONTAINER(QList, QVariant)
+ TEST_SEQUENTIAL_CONTAINER(std::vector, QVariant)
+ TEST_SEQUENTIAL_CONTAINER(std::list, QVariant)
{
QList<QSharedPointer<QObject> > sharedPointerList;
@@ -1395,6 +1402,31 @@ void tst_QMetaType::automaticTemplateRegistration()
QCOMPARE(QVariant::fromValue(variantMap).value<QVariantMap>().value(QStringLiteral("4")), QVariant(2));
}
{
+ typedef std::map<int, int> IntIntMap;
+ IntIntMap intIntMap;
+ intIntMap[4] = 2;
+ QCOMPARE(QVariant::fromValue(intIntMap).value<IntIntMap>()[4], 2);
+ }
+ {
+ typedef std::map<int, uint> StdIntUIntMap;
+ StdIntUIntMap intUIntMap;
+ intUIntMap[4] = 2;
+ QCOMPARE(QVariant::fromValue(intUIntMap).value<StdIntUIntMap>()[4], (uint)2);
+ }
+ {
+ typedef std::map<int, CustomObject*> StdMapIntCustomObject ;
+ StdMapIntCustomObject intComparableMap;
+ CustomObject *o = 0;
+ intComparableMap[4] = o;
+ QCOMPARE(QVariant::fromValue(intComparableMap).value<StdMapIntCustomObject >()[4], o);
+ }
+ {
+ typedef std::map<QString, QVariant> StdMapStringVariant;
+ StdMapStringVariant variantMap;
+ variantMap[QStringLiteral("4")] = 2;
+ QCOMPARE(QVariant::fromValue(variantMap).value<StdMapStringVariant>()[QStringLiteral("4")], QVariant(2));
+ }
+ {
typedef QPair<int, int> IntIntPair;
IntIntPair intIntPair = qMakePair(4, 2);
QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
@@ -1412,6 +1444,25 @@ void tst_QMetaType::automaticTemplateRegistration()
QCOMPARE(QVariant::fromValue(intComparablePair).value<IntComparablePair>().second, m);
}
{
+ typedef std::pair<int, int> IntIntPair;
+ IntIntPair intIntPair = std::make_pair(4, 2);
+ QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().first, 4);
+ QCOMPARE(QVariant::fromValue(intIntPair).value<IntIntPair>().second, 2);
+ }
+ {
+ typedef std::pair<int, uint> StdIntUIntPair;
+ StdIntUIntPair intUIntPair = std::make_pair<int, uint>(4, 2);
+ QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().first, 4);
+ QCOMPARE(QVariant::fromValue(intUIntPair).value<StdIntUIntPair>().second, (uint)2);
+ }
+ {
+ typedef std::pair<int, CustomQObject*> StdIntComparablePair;
+ CustomQObject* o = 0;
+ StdIntComparablePair intComparablePair = std::make_pair(4, o);
+ QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().first, 4);
+ QCOMPARE(QVariant::fromValue(intComparablePair).value<StdIntComparablePair>().second, o);
+ }
+ {
typedef QHash<int, UnregisteredType> IntUnregisteredTypeHash;
QVERIFY(qRegisterMetaType<IntUnregisteredTypeHash>("IntUnregisteredTypeHash") > 0);
}
@@ -1446,17 +1497,14 @@ void tst_QMetaType::automaticTemplateRegistration()
F(uint, __VA_ARGS__) \
F(qlonglong, __VA_ARGS__) \
F(qulonglong, __VA_ARGS__) \
- F(double, __VA_ARGS__) \
F(long, __VA_ARGS__) \
F(short, __VA_ARGS__) \
F(char, __VA_ARGS__) \
F(ulong, __VA_ARGS__) \
F(ushort, __VA_ARGS__) \
F(uchar, __VA_ARGS__) \
- F(float, __VA_ARGS__) \
F(QObject*, __VA_ARGS__) \
- F(QString, __VA_ARGS__) \
- F(CustomMovable, __VA_ARGS__)
+ F(QString, __VA_ARGS__)
#define CREATE_AND_VERIFY_CONTAINER(CONTAINER, ...) \
@@ -1774,6 +1822,366 @@ void tst_QMetaType::constRefs()
#endif
}
+struct CustomConvertibleType
+{
+ explicit CustomConvertibleType(const QVariant &foo = QVariant()) : m_foo(foo) {}
+ virtual ~CustomConvertibleType() {}
+ QString toString() const { return m_foo.toString(); }
+ operator QPoint() const { return QPoint(12, 34); }
+ template<typename To>
+ To convert() const { return s_value.value<To>();}
+ template<typename To>
+ To convertOk(bool *ok) const { *ok = s_ok; return s_value.value<To>();}
+
+ QVariant m_foo;
+ static QVariant s_value;
+ static bool s_ok;
+};
+
+bool operator<(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
+{ return lhs.m_foo < rhs.m_foo; }
+bool operator==(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
+{ return lhs.m_foo == rhs.m_foo; }
+bool operator!=(const CustomConvertibleType &lhs, const CustomConvertibleType &rhs)
+{ return !operator==(lhs, rhs); }
+
+QVariant CustomConvertibleType::s_value;
+bool CustomConvertibleType::s_ok = true;
+
+struct CustomConvertibleType2
+{
+ // implicit
+ CustomConvertibleType2(const CustomConvertibleType &t = CustomConvertibleType())
+ : m_foo(t.m_foo) {}
+ virtual ~CustomConvertibleType2() {}
+
+ QVariant m_foo;
+};
+
+struct CustomDebugStreamableType
+{
+ QString toString() const { return "test"; }
+};
+
+QDebug operator<<(QDebug dbg, const CustomDebugStreamableType&)
+{
+ return dbg << "string-content";
+}
+
+bool operator==(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
+{ return lhs.m_foo == rhs.m_foo; }
+bool operator!=(const CustomConvertibleType2 &lhs, const CustomConvertibleType2 &rhs)
+{ return !operator==(lhs, rhs); }
+
+Q_DECLARE_METATYPE(CustomConvertibleType);
+Q_DECLARE_METATYPE(CustomConvertibleType2);
+Q_DECLARE_METATYPE(CustomDebugStreamableType);
+
+template<typename T, typename U>
+U convert(const T &t)
+{
+ return t;
+}
+
+template<typename From>
+struct ConvertFunctor
+{
+ CustomConvertibleType operator()(const From& f) const
+ {
+ return CustomConvertibleType(QVariant::fromValue(f));
+ }
+};
+
+template<typename From, typename To>
+bool hasRegisteredConverterFunction()
+{
+ return QMetaType::hasRegisteredConverterFunction<From, To>();
+}
+
+template<typename From, typename To>
+void testCustomTypeNotYetConvertible()
+{
+ QVERIFY((!hasRegisteredConverterFunction<From, To>()));
+ QVERIFY((!QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
+}
+
+template<typename From, typename To>
+void testCustomTypeConvertible()
+{
+ QVERIFY((hasRegisteredConverterFunction<From, To>()));
+ QVERIFY((QVariant::fromValue<From>(From()).canConvert(qMetaTypeId<To>())));
+}
+
+void customTypeNotYetConvertible()
+{
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QString>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, bool>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, int>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, double>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, float>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QRect>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QRectF>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QPoint>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QPointF>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QSize>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QSizeF>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QLine>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QLineF>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, QChar>();
+ testCustomTypeNotYetConvertible<QString, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<bool, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<int, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<double, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<float, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QRect, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QRectF, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QPoint, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QPointF, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QSize, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QSizeF, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QLine, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QLineF, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<QChar, CustomConvertibleType>();
+ testCustomTypeNotYetConvertible<CustomConvertibleType, CustomConvertibleType2>();
+}
+
+void registerCustomTypeConversions()
+{
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QString>(&CustomConvertibleType::convertOk<QString>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, bool>(&CustomConvertibleType::convert<bool>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, int>(&CustomConvertibleType::convertOk<int>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, double>(&CustomConvertibleType::convert<double>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, float>(&CustomConvertibleType::convertOk<float>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRect>(&CustomConvertibleType::convert<QRect>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QRectF>(&CustomConvertibleType::convertOk<QRectF>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPoint>(convert<CustomConvertibleType,QPoint>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QPointF>(&CustomConvertibleType::convertOk<QPointF>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSize>(&CustomConvertibleType::convert<QSize>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QSizeF>(&CustomConvertibleType::convertOk<QSizeF>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLine>(&CustomConvertibleType::convert<QLine>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QLineF>(&CustomConvertibleType::convertOk<QLineF>)));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, QChar>(&CustomConvertibleType::convert<QChar>)));
+ QVERIFY((QMetaType::registerConverter<QString, CustomConvertibleType>(ConvertFunctor<QString>())));
+ QVERIFY((QMetaType::registerConverter<bool, CustomConvertibleType>(ConvertFunctor<bool>())));
+ QVERIFY((QMetaType::registerConverter<int, CustomConvertibleType>(ConvertFunctor<int>())));
+ QVERIFY((QMetaType::registerConverter<double, CustomConvertibleType>(ConvertFunctor<double>())));
+ QVERIFY((QMetaType::registerConverter<float, CustomConvertibleType>(ConvertFunctor<float>())));
+ QVERIFY((QMetaType::registerConverter<QRect, CustomConvertibleType>(ConvertFunctor<QRect>())));
+ QVERIFY((QMetaType::registerConverter<QRectF, CustomConvertibleType>(ConvertFunctor<QRectF>())));
+ QVERIFY((QMetaType::registerConverter<QPoint, CustomConvertibleType>(ConvertFunctor<QPoint>())));
+ QVERIFY((QMetaType::registerConverter<QPointF, CustomConvertibleType>(ConvertFunctor<QPointF>())));
+ QVERIFY((QMetaType::registerConverter<QSize, CustomConvertibleType>(ConvertFunctor<QSize>())));
+ QVERIFY((QMetaType::registerConverter<QSizeF, CustomConvertibleType>(ConvertFunctor<QSizeF>())));
+ QVERIFY((QMetaType::registerConverter<QLine, CustomConvertibleType>(ConvertFunctor<QLine>())));
+ QVERIFY((QMetaType::registerConverter<QLineF, CustomConvertibleType>(ConvertFunctor<QLineF>())));
+ QVERIFY((QMetaType::registerConverter<QChar, CustomConvertibleType>(ConvertFunctor<QChar>())));
+ QVERIFY((QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
+ QTest::ignoreMessage(QtWarningMsg, "Type conversion already registered from type CustomConvertibleType to type CustomConvertibleType2");
+ QVERIFY((!QMetaType::registerConverter<CustomConvertibleType, CustomConvertibleType2>()));
+}
+
+void tst_QMetaType::convertCustomType_data()
+{
+ customTypeNotYetConvertible();
+ registerCustomTypeConversions();
+
+ QTest::addColumn<bool>("ok");
+ QTest::addColumn<QString>("testQString");
+ QTest::addColumn<bool>("testBool");
+ QTest::addColumn<int>("testInt");
+ QTest::addColumn<double>("testDouble");
+ QTest::addColumn<float>("testFloat");
+ QTest::addColumn<QRect>("testQRect");
+ QTest::addColumn<QRectF>("testQRectF");
+ QTest::addColumn<QPoint>("testQPoint");
+ QTest::addColumn<QPointF>("testQPointF");
+ QTest::addColumn<QSize>("testQSize");
+ QTest::addColumn<QSizeF>("testQSizeF");
+ QTest::addColumn<QLine>("testQLine");
+ QTest::addColumn<QLineF>("testQLineF");
+ QTest::addColumn<QChar>("testQChar");
+ QTest::addColumn<CustomConvertibleType>("testCustom");
+
+ QTest::newRow("default") << true
+ << QString::fromLatin1("string") << true << 15
+ << double(3.14) << float(3.6) << QRect(1, 2, 3, 4)
+ << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34)
+ << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8)
+ << QLine(3, 9, 29, 4) << QLineF(38.9, 28.9, 102.3, 0.0)
+ << QChar('Q') << CustomConvertibleType(QString::fromLatin1("test"));
+ QTest::newRow("not ok") << false
+ << QString::fromLatin1("string") << true << 15
+ << double(3.14) << float(3.6) << QRect(1, 2, 3, 4)
+ << QRectF(1.4, 1.9, 10.9, 40.2) << QPoint(12, 34)
+ << QPointF(9.2, 2.7) << QSize(4, 9) << QSizeF(3.3, 9.8)
+ << QLine(3, 9, 29, 4) << QLineF()
+ << QChar('Q') << CustomConvertibleType(42);
+}
+
+void tst_QMetaType::convertCustomType()
+{
+ QFETCH(bool, ok);
+ CustomConvertibleType::s_ok = ok;
+
+ CustomConvertibleType t;
+ QVariant v = QVariant::fromValue(t);
+ QFETCH(QString, testQString);
+ CustomConvertibleType::s_value = testQString;
+ QCOMPARE(v.toString(), ok ? testQString : QString());
+ QCOMPARE(v.value<QString>(), ok ? testQString : QString());
+ QVERIFY(CustomConvertibleType::s_value.canConvert<CustomConvertibleType>());
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toString()), testQString);
+
+ QFETCH(bool, testBool);
+ CustomConvertibleType::s_value = testBool;
+ QCOMPARE(v.toBool(), testBool);
+ QCOMPARE(v.value<bool>(), testBool);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toBool()), testBool);
+
+ QFETCH(int, testInt);
+ CustomConvertibleType::s_value = testInt;
+ QCOMPARE(v.toInt(), ok ? testInt : 0);
+ QCOMPARE(v.value<int>(), ok ? testInt : 0);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toInt()), testInt);
+
+ QFETCH(double, testDouble);
+ CustomConvertibleType::s_value = testDouble;
+ QCOMPARE(v.toDouble(), testDouble);
+ QCOMPARE(v.value<double>(), testDouble);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toDouble()), testDouble);
+
+ QFETCH(float, testFloat);
+ CustomConvertibleType::s_value = testFloat;
+ QCOMPARE(v.toFloat(), ok ? testFloat : 0.0);
+ QCOMPARE(v.value<float>(), ok ? testFloat : 0.0);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toFloat()), testFloat);
+
+ QFETCH(QRect, testQRect);
+ CustomConvertibleType::s_value = testQRect;
+ QCOMPARE(v.toRect(), testQRect);
+ QCOMPARE(v.value<QRect>(), testQRect);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRect()), testQRect);
+
+ QFETCH(QRectF, testQRectF);
+ CustomConvertibleType::s_value = testQRectF;
+ QCOMPARE(v.toRectF(), ok ? testQRectF : QRectF());
+ QCOMPARE(v.value<QRectF>(), ok ? testQRectF : QRectF());
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toRectF()), testQRectF);
+
+ QFETCH(QPoint, testQPoint);
+ CustomConvertibleType::s_value = testQPoint;
+ QCOMPARE(v.toPoint(), testQPoint);
+ QCOMPARE(v.value<QPoint>(), testQPoint);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPoint()), testQPoint);
+
+ QFETCH(QPointF, testQPointF);
+ CustomConvertibleType::s_value = testQPointF;
+ QCOMPARE(v.toPointF(), ok ? testQPointF : QPointF());
+ QCOMPARE(v.value<QPointF>(), ok ? testQPointF : QPointF());
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toPointF()), testQPointF);
+
+ QFETCH(QSize, testQSize);
+ CustomConvertibleType::s_value = testQSize;
+ QCOMPARE(v.toSize(), testQSize);
+ QCOMPARE(v.value<QSize>(), testQSize);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSize()), testQSize);
+
+ QFETCH(QSizeF, testQSizeF);
+ CustomConvertibleType::s_value = testQSizeF;
+ QCOMPARE(v.toSizeF(), ok ? testQSizeF : QSizeF());
+ QCOMPARE(v.value<QSizeF>(), ok ? testQSizeF : QSizeF());
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toSizeF()), testQSizeF);
+
+ QFETCH(QLine, testQLine);
+ CustomConvertibleType::s_value = testQLine;
+ QCOMPARE(v.toLine(), testQLine);
+ QCOMPARE(v.value<QLine>(), testQLine);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLine()), testQLine);
+
+ QFETCH(QLineF, testQLineF);
+ CustomConvertibleType::s_value = testQLineF;
+ QCOMPARE(v.toLineF(), ok ? testQLineF : QLineF());
+ QCOMPARE(v.value<QLineF>(), ok ? testQLineF : QLineF());
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toLineF()), testQLineF);
+
+ QFETCH(QChar, testQChar);
+ CustomConvertibleType::s_value = testQChar;
+ QCOMPARE(v.toChar(), testQChar);
+ QCOMPARE((CustomConvertibleType::s_value.value<CustomConvertibleType>().m_foo.toChar()), testQChar);
+
+ QFETCH(CustomConvertibleType, testCustom);
+ v = QVariant::fromValue(testCustom);
+ QVERIFY(v.canConvert(::qMetaTypeId<CustomConvertibleType2>()));
+ QCOMPARE(v.value<CustomConvertibleType2>().m_foo, testCustom.m_foo);
+}
+
+void tst_QMetaType::compareCustomType_data()
+{
+ QMetaType::registerComparators<CustomConvertibleType>();
+
+ QTest::addColumn<QVariantList>("unsorted");
+ QTest::addColumn<QVariantList>("sorted");
+
+ QTest::newRow("int") << (QVariantList() << 37 << 458 << 1 << 243 << -4 << 383)
+ << (QVariantList() << -4 << 1 << 37 << 243 << 383 << 458);
+
+ QTest::newRow("dobule") << (QVariantList() << 4934.93 << 0.0 << 302.39 << -39.0)
+ << (QVariantList() << -39.0 << 0.0 << 302.39 << 4934.93);
+
+ QTest::newRow("QString") << (QVariantList() << "Hello" << "World" << "this" << "is" << "a" << "test")
+ << (QVariantList() << "a" << "Hello" << "is" << "test" << "this" << "World");
+
+ QTest::newRow("QTime") << (QVariantList() << QTime(14, 39) << QTime(0, 0) << QTime(18, 18) << QTime(9, 27))
+ << (QVariantList() << QTime(0, 0) << QTime(9, 27) << QTime(14, 39) << QTime(18, 18));
+
+ QTest::newRow("QDate") << (QVariantList() << QDate(2013, 3, 23) << QDate(1900, 12, 1) << QDate(2001, 2, 2) << QDate(1982, 12, 16))
+ << (QVariantList() << QDate(1900, 12, 1) << QDate(1982, 12, 16) << QDate(2001, 2, 2) << QDate(2013, 3, 23));
+
+ QTest::newRow("mixed") << (QVariantList() << "Hello" << "World" << QChar('a') << 38 << QChar('z') << -39 << 4.6)
+ << (QVariantList() << -39 << 4.6 << 38 << QChar('a') << "Hello" << "World" << QChar('z'));
+
+ QTest::newRow("custom") << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(100)) << QVariant::fromValue(CustomConvertibleType(50)))
+ << (QVariantList() << QVariant::fromValue(CustomConvertibleType(1)) << QVariant::fromValue(CustomConvertibleType(50)) << QVariant::fromValue(CustomConvertibleType(100)));
+}
+
+void tst_QMetaType::compareCustomType()
+{
+ QFETCH(QVariantList, unsorted);
+ QFETCH(QVariantList, sorted);
+ qSort(unsorted);
+ QCOMPARE(unsorted, sorted);
+}
+
+struct MessageHandlerCustom : public MessageHandler
+{
+ MessageHandlerCustom(const int typeId)
+ : MessageHandler(typeId, handler)
+ {}
+ static void handler(QtMsgType, const QMessageLogContext &, const QString &msg)
+ {
+ QCOMPARE(msg.trimmed(), expectedMessage.trimmed());
+ }
+ static QString expectedMessage;
+};
+
+QString MessageHandlerCustom::expectedMessage;
+
+void tst_QMetaType::customDebugStream()
+{
+ MessageHandlerCustom handler(::qMetaTypeId<CustomDebugStreamableType>());
+ QVariant v1 = QVariant::fromValue(CustomDebugStreamableType());
+ handler.expectedMessage = "QVariant(CustomDebugStreamableType, )";
+ qDebug() << v1;
+
+ QMetaType::registerConverter<CustomDebugStreamableType, QString>(&CustomDebugStreamableType::toString);
+ handler.expectedMessage = "QVariant(CustomDebugStreamableType, \"test\")";
+ qDebug() << v1;
+
+ QMetaType::registerDebugStreamOperator<CustomDebugStreamableType>();
+ handler.expectedMessage = "QVariant(CustomDebugStreamableType, string-content)";
+ qDebug() << v1;
+}
+
// Compile-time test, it should be possible to register function pointer types
class Undefined;
@@ -1781,11 +2189,15 @@ typedef Undefined (*UndefinedFunction0)();
typedef Undefined (*UndefinedFunction1)(Undefined);
typedef Undefined (*UndefinedFunction2)(Undefined, Undefined);
typedef Undefined (*UndefinedFunction3)(Undefined, Undefined, Undefined);
+typedef Undefined (*UndefinedFunction4)(Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined, Undefined);
Q_DECLARE_METATYPE(UndefinedFunction0);
Q_DECLARE_METATYPE(UndefinedFunction1);
Q_DECLARE_METATYPE(UndefinedFunction2);
Q_DECLARE_METATYPE(UndefinedFunction3);
+#ifdef Q_COMPILER_VARIADIC_TEMPLATES
+Q_DECLARE_METATYPE(UndefinedFunction4);
+#endif
QTEST_MAIN(tst_QMetaType)
#include "tst_qmetatype.moc"
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 1cdf39018b..05d81c2bd1 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -90,7 +90,7 @@ private slots:
void thread();
void thread0();
void moveToThread();
- void sender();
+ void senderTest();
void declareInterface();
void qpointerResetBeforeDestroyedSignal();
void testUserData();
@@ -144,8 +144,13 @@ private slots:
void connectPrivateSlots();
void connectFunctorArgDifference();
void connectFunctorOverloads();
+ void connectFunctorQueued();
+ void connectFunctorWithContext();
+ void connectStaticSlotWithObject();
void disconnectDoesNotLeakFunctor();
+ void contextDoesNotLeakFunctor();
void connectBase();
+ void qmlConnect();
};
struct QObjectCreatedOnShutdown
@@ -2061,7 +2066,7 @@ void tst_QObject::metamethod()
m = mobj->method(mobj->indexOfMethod("signal5()"));
QVERIFY(m.methodSignature() == "signal5()");
QVERIFY(m.methodType() == QMetaMethod::Signal);
- QVERIFY(m.access() == QMetaMethod::Protected);
+ QVERIFY(m.access() == QMetaMethod::Public);
QVERIFY(!(m.attributes() & QMetaMethod::Scriptable));
QVERIFY((m.attributes() & QMetaMethod::Compatibility));
@@ -2151,7 +2156,7 @@ signals:
void theSignal();
};
-void tst_QObject::sender()
+void tst_QObject::senderTest()
{
{
SuperObject sender;
@@ -5601,6 +5606,129 @@ void tst_QObject::connectFunctorArgDifference()
QVERIFY(true);
}
+class ContextObject : public QObject
+{
+ Q_OBJECT
+public:
+ void compareSender(QObject *s) { QCOMPARE(s, sender()); }
+};
+
+struct SlotArgFunctor
+{
+ SlotArgFunctor(int *s) : status(s), context(Q_NULLPTR), sender(Q_NULLPTR) {}
+ SlotArgFunctor(ContextObject *context, QObject *sender, int *s) : status(s), context(context), sender(sender) {}
+ void operator()() { *status = 2; if (context) context->compareSender(sender); }
+
+protected:
+ int *status;
+ ContextObject *context;
+ QObject *sender;
+};
+
+void tst_QObject::connectFunctorQueued()
+{
+ int status = 1;
+ SenderObject obj;
+ QEventLoop e;
+
+ connect(&obj, &SenderObject::signal1, this, SlotArgFunctor(&status), Qt::QueuedConnection);
+ connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
+
+ obj.emitSignal1();
+ QCOMPARE(status, 1);
+ e.exec();
+ QCOMPARE(status, 2);
+
+#if defined(Q_COMPILER_LAMBDA)
+ status = 1;
+ connect(&obj, &SenderObject::signal1, this, [&status] { status = 2; }, Qt::QueuedConnection);
+
+ obj.emitSignal1();
+ QCOMPARE(status, 1);
+ e.exec();
+ QCOMPARE(status, 2);
+#endif
+}
+
+void tst_QObject::connectFunctorWithContext()
+{
+ int status = 1;
+ SenderObject obj;
+ QMetaObject::Connection handle;
+ ContextObject *context = new ContextObject;
+ QEventLoop e;
+
+ connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status));
+ connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
+
+ // When the context gets deleted, the connection should decay and the signal shouldn't trigger
+ // The connection is queued to make sure the destroyed signal propagates correctly and
+ // cuts the connection.
+ connect(context, &QObject::destroyed, &obj, &SenderObject::signal1, Qt::QueuedConnection);
+ context->deleteLater();
+
+ QCOMPARE(status, 1);
+ e.exec();
+ QCOMPARE(status, 1);
+
+ // Check the sender arg is set correctly in the context
+ context = new ContextObject;
+
+ connect(&obj, &SenderObject::signal1, context,
+ SlotArgFunctor(context, &obj, &status), Qt::QueuedConnection);
+
+ obj.emitSignal1();
+ QCOMPARE(status, 1);
+ e.exec();
+ QCOMPARE(status, 2);
+
+#if defined(Q_COMPILER_LAMBDA)
+ status = 1;
+ connect(&obj, &SenderObject::signal1, this, [this, &status, &obj] { status = 2; QCOMPARE(sender(), &obj); }, Qt::QueuedConnection);
+
+ obj.emitSignal1();
+ QCOMPARE(status, 1);
+ e.exec();
+ QCOMPARE(status, 2);
+#endif
+
+ // Free
+ context->deleteLater();
+}
+
+static int s_static_slot_checker = 1;
+
+class StaticSlotChecker : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ static void staticSlot() { s_static_slot_checker = 2; }
+};
+
+void tst_QObject::connectStaticSlotWithObject()
+{
+ SenderObject sender;
+ StaticSlotChecker *receiver = new StaticSlotChecker;
+ QEventLoop e;
+
+ QVERIFY(connect(&sender, &SenderObject::signal1, receiver, &StaticSlotChecker::staticSlot, Qt::QueuedConnection));
+ connect(&sender, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
+
+ sender.emitSignal1();
+ QCOMPARE(s_static_slot_checker, 1);
+ e.exec();
+ QCOMPARE(s_static_slot_checker, 2);
+
+ s_static_slot_checker = 1;
+
+ connect(receiver, &QObject::destroyed, &sender, &SenderObject::signal1, Qt::QueuedConnection);
+ receiver->deleteLater();
+
+ QCOMPARE(s_static_slot_checker, 1);
+ e.exec();
+ QCOMPARE(s_static_slot_checker, 1);
+}
+
struct ComplexFunctor {
ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
void operator()(int a, int b) {
@@ -5773,6 +5901,23 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
}
QCOMPARE(countedStructObjectsCount, 0);
{
+ GetSenderObject obj;
+ QMetaObject::Connection c;
+ {
+ CountedStruct s(&obj);
+ QObject context;
+ QCOMPARE(countedStructObjectsCount, 1);
+
+ c = connect(&obj, &GetSenderObject::aSignal, &context, s);
+ QVERIFY(c);
+ QCOMPARE(countedStructObjectsCount, 2);
+ QVERIFY(QObject::disconnect(c));
+ QCOMPARE(countedStructObjectsCount, 1);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ {
QMetaObject::Connection c1, c2;
{
CountedStruct s;
@@ -5856,6 +6001,67 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
QCOMPARE(countedStructObjectsCount, 0);
}
+void tst_QObject::contextDoesNotLeakFunctor()
+{
+ QCOMPARE(countedStructObjectsCount, 0);
+ {
+ QMetaObject::Connection c;
+ {
+ QEventLoop e;
+ ContextObject *context = new ContextObject;
+ SenderObject obj;
+
+ connect(&obj, &SenderObject::signal1, context, CountedStruct());
+ connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
+ context->deleteLater();
+
+ QCOMPARE(countedStructObjectsCount, 1);
+ e.exec();
+ QCOMPARE(countedStructObjectsCount, 0);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ {
+ GetSenderObject obj;
+ QMetaObject::Connection c;
+ {
+ CountedStruct s(&obj);
+ QEventLoop e;
+ ContextObject *context = new ContextObject;
+ QCOMPARE(countedStructObjectsCount, 1);
+
+ connect(&obj, &GetSenderObject::aSignal, context, s);
+ QCOMPARE(countedStructObjectsCount, 2);
+
+ connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
+ context->deleteLater();
+
+ e.exec();
+ QCOMPARE(countedStructObjectsCount, 1);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+ {
+#if defined(Q_COMPILER_LAMBDA)
+ CountedStruct s;
+ QEventLoop e;
+ ContextObject *context = new ContextObject;
+ QCOMPARE(countedStructObjectsCount, 1);
+ QTimer timer;
+
+ connect(&timer, &QTimer::timeout, context, [s](){});
+ QCOMPARE(countedStructObjectsCount, 2);
+ connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
+ context->deleteLater();
+ e.exec();
+ QCOMPARE(countedStructObjectsCount, 1);
+#endif // Q_COMPILER_LAMBDA
+ }
+ QCOMPARE(countedStructObjectsCount, 0);
+}
+
class SubSender : public SenderObject {
Q_OBJECT
};
@@ -5879,6 +6085,60 @@ void tst_QObject::connectBase()
QCOMPARE( r1.count_slot3, 1 );
}
+struct QmlReceiver : public QtPrivate::QSlotObjectBase
+{
+ int callCount;
+ void *magic;
+
+ QmlReceiver()
+ : QtPrivate::QSlotObjectBase(&impl)
+ , callCount(0)
+ , magic(0)
+ {}
+
+ static void impl(int which, QSlotObjectBase *this_, QObject *, void **metaArgs, bool *ret)
+ {
+ switch (which) {
+ case Destroy: delete static_cast<QmlReceiver*>(this_); return;
+ case Call: static_cast<QmlReceiver*>(this_)->callCount++; return;
+ case Compare: *ret = static_cast<QmlReceiver*>(this_)->magic == metaArgs[0]; return;
+ case NumOperations: break;
+ }
+ }
+};
+
+void tst_QObject::qmlConnect()
+{
+#ifdef QT_BUILD_INTERNAL
+ SenderObject sender;
+ QmlReceiver *receiver = new QmlReceiver;
+ receiver->magic = receiver;
+ receiver->ref();
+
+ QVERIFY(QObjectPrivate::connect(&sender, sender.metaObject()->indexOfSignal("signal1()"),
+ receiver, Qt::AutoConnection));
+
+ QCOMPARE(receiver->callCount, 0);
+ sender.emitSignal1();
+ QCOMPARE(receiver->callCount, 1);
+
+ void *a[] = {
+ receiver
+ };
+ QVERIFY(QObjectPrivate::disconnect(&sender, sender.metaObject()->indexOfSignal("signal1()"), reinterpret_cast<void**>(&a)));
+
+ sender.emitSignal1();
+ QCOMPARE(receiver->callCount, 1);
+
+ receiver->destroyIfLastRef();
+#else
+ QSKIP("Needs QT_BUILD_INTERNAL");
+#endif
+}
+
+// Test for QtPrivate::HasQ_OBJECT_Macro
+Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
+Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
QTEST_MAIN(tst_QObject)
#include "tst_qobject.moc"
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index 4d862f4fc5..422bd63163 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -154,6 +154,8 @@ private slots:
void qvariant_cast_QObject_data();
void qvariant_cast_QObject();
void qvariant_cast_QObject_derived();
+ void qvariant_cast_QObject_wrapper();
+ void qvariant_cast_QSharedPointerQObject();
void toLocale();
@@ -242,6 +244,9 @@ private slots:
void saveNewBuiltinWithOldStream();
void implicitConstruction();
+
+ void iterateContainerElements();
+ void pairElements();
private:
void dataStream_data(QDataStream::Version version);
void loadQVariantFromDataStream(QDataStream::Version version);
@@ -2232,6 +2237,182 @@ void tst_QVariant::qvariant_cast_QObject_derived()
}
}
+struct QObjectWrapper
+{
+ explicit QObjectWrapper(QObject *o = 0) : obj(o) {}
+
+ QObject* getObject() const {
+ return obj;
+ }
+private:
+ QObject *obj;
+};
+
+Q_DECLARE_METATYPE(QObjectWrapper)
+
+struct Converter
+{
+ Converter() {}
+
+ QObject* operator()(const QObjectWrapper &f) const
+ {
+ return f.getObject();
+ }
+};
+
+namespace MyNS {
+
+template<typename T>
+class SmartPointer
+{
+ T* pointer;
+public:
+ typedef T element_type;
+ explicit SmartPointer(T *t = 0)
+ : pointer(t)
+ {
+ }
+
+ T* operator->() const { return pointer; }
+};
+
+template<typename T>
+struct SequentialContainer
+{
+ typedef T value_type;
+ typedef const T* const_iterator;
+ T t;
+ const_iterator begin() const { return &t; }
+ const_iterator end() const { return &t + 1; }
+};
+
+template<typename T, typename U>
+struct AssociativeContainer : public std::map<T, U>
+{
+};
+
+}
+
+Q_DECLARE_SMART_POINTER_METATYPE(MyNS::SmartPointer)
+
+Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(MyNS::SequentialContainer)
+Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(MyNS::AssociativeContainer)
+
+// Test that explicit declaration does not degrade features.
+Q_DECLARE_METATYPE(MyNS::SmartPointer<int>)
+Q_DECLARE_METATYPE(MyNS::SmartPointer<QIODevice>)
+Q_DECLARE_METATYPE(QSharedPointer<QIODevice>)
+
+void tst_QVariant::qvariant_cast_QObject_wrapper()
+{
+ QMetaType::registerConverter<QObjectWrapper, QObject*>(&QObjectWrapper::getObject);
+
+ CustomQObjectDerived *object = new CustomQObjectDerived(this);
+ QObjectWrapper wrapper(object);
+ QVariant v = QVariant::fromValue(wrapper);
+ QCOMPARE(v.value<QObject*>(), object);
+ v.convert(qMetaTypeId<QObject*>());
+ QCOMPARE(v.value<QObject*>(), object);
+
+ MyNS::SequentialContainer<int> sc;
+ sc.t = 47;
+ MyNS::AssociativeContainer<int, short> ac;
+
+ QVariant::fromValue(sc);
+ QVariant::fromValue(ac);
+
+ {
+ QFile *f = new QFile(this);
+ MyNS::SmartPointer<QFile> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+ {
+ QFile *f = new QFile(this);
+ QPointer<QFile> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+ {
+ QFile *f = new QFile(this);
+ QWeakPointer<QFile> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+ {
+ QFile *f = new QFile(this);
+ QSharedPointer<QFile> sp(f);
+ QWeakPointer<QFile> wp = sp.toWeakRef();
+ QVariant wpVar = QVariant::fromValue(wp);
+ QVERIFY(wpVar.canConvert<QObject*>());
+ QCOMPARE(f, wpVar.value<QObject*>());
+ }
+ {
+ QFile *f = new QFile(this);
+ QSharedPointer<QFile> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+ {
+ QIODevice *f = new QFile(this);
+ MyNS::SmartPointer<QIODevice> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+ {
+ QIODevice *f = new QFile(this);
+ QSharedPointer<QIODevice> sp(f);
+ QVariant spVar = QVariant::fromValue(sp);
+ QVERIFY(spVar.canConvert<QObject*>());
+ QCOMPARE(f, spVar.value<QObject*>());
+ }
+
+ // Compile tests:
+ qRegisterMetaType<MyNS::SmartPointer<int> >();
+ // Not declared as a metatype:
+ qRegisterMetaType<MyNS::SmartPointer<double> >("MyNS::SmartPointer<double>");
+}
+
+void tst_QVariant::qvariant_cast_QSharedPointerQObject()
+{
+ // ensure no problems between this form and the auto-registering in QVariant::fromValue
+ qRegisterMetaType<QSharedPointer<QObject> >("QSharedPointer<QObject>");
+
+ QObject *rawptr = new QObject;
+ QSharedPointer<QObject> strong(rawptr);
+ QWeakPointer<QObject> weak(strong);
+ QPointer<QObject> qptr(rawptr);
+
+ QVariant v = QVariant::fromValue(strong);
+ QCOMPARE(v.value<QSharedPointer<QObject> >(), strong);
+
+ // clear our QSP; the copy inside the variant should keep the object alive
+ strong.clear();
+
+ // check that the object didn't get deleted
+ QVERIFY(!weak.isNull());
+ QVERIFY(!qptr.isNull());
+
+ strong = qvariant_cast<QSharedPointer<QObject> >(v);
+ QCOMPARE(strong.data(), rawptr);
+ QVERIFY(strong == weak);
+
+ // now really delete the object and verify
+ strong.clear();
+ v.clear();
+ QVERIFY(weak.isNull());
+ QVERIFY(qptr.isNull());
+
+ // compile test:
+ // QVariant::fromValue has already called this function
+ qRegisterMetaType<QSharedPointer<QObject> >();
+}
+
void tst_QVariant::convertToQUint8() const
{
/* qint8. */
@@ -3392,5 +3573,362 @@ void tst_QVariant::saveNewBuiltinWithOldStream()
QCOMPARE(int(data.constData()[3]), 0);
}
+template<typename Container, typename Value_Type = typename Container::value_type>
+struct ContainerAPI
+{
+ static void insert(Container &container, typename Container::value_type value)
+ {
+ container.push_back(value);
+ }
+
+ static bool compare(const QVariant &variant, typename Container::value_type value)
+ {
+ return variant.value<typename Container::value_type>() == value;
+ }
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+
+template<typename Container>
+struct ContainerAPI<Container, QVariant>
+{
+ static void insert(Container &container, int value)
+ {
+ container.push_back(QVariant::fromValue(value));
+ }
+
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+
+template<typename Container>
+struct ContainerAPI<Container, QString>
+{
+ static void insert(Container &container, int value)
+ {
+ container.push_back(QString::number(value));
+ }
+
+ static bool compare(const QVariant &variant, QString value)
+ {
+ return variant.value<QString>() == value;
+ }
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+
+// We have no built-in defines to check the stdlib features.
+// #define TEST_FORWARD_LIST
+
+#ifdef TEST_FORWARD_LIST
+#include <forward_list>
+
+Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::forward_list)
+
+// Test that explicit declaration does not degrade features.
+Q_DECLARE_METATYPE(std::forward_list<int>)
+
+template<typename Value_Type>
+struct ContainerAPI<std::forward_list<Value_Type> >
+{
+ static void insert(std::forward_list<Value_Type> &container, Value_Type value)
+ {
+ container.push_front(value);
+ }
+ static bool compare(const QVariant &variant, Value_Type value)
+ {
+ return variant.value<Value_Type>() == value;
+ }
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+
+template<>
+struct ContainerAPI<std::forward_list<QVariant> >
+{
+ static void insert(std::forward_list<QVariant> &container, int value)
+ {
+ container.push_front(QVariant::fromValue(value));
+ }
+
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+
+template<>
+struct ContainerAPI<std::forward_list<QString> >
+{
+ static void insert(std::forward_list<QString> &container, int value)
+ {
+ container.push_front(QString::number(value));
+ }
+ static bool compare(const QVariant &variant, QString value)
+ {
+ return variant.value<QString>() == value;
+ }
+ static bool compare(QVariant variant, const QVariant &value)
+ {
+ return variant == value;
+ }
+};
+#endif
+
+template<typename Container>
+struct KeyGetter
+{
+ static const typename Container::key_type & get(const typename Container::const_iterator &it)
+ {
+ return it.key();
+ }
+ static const typename Container::mapped_type & value(const typename Container::const_iterator &it)
+ {
+ return it.value();
+ }
+};
+
+template<typename T, typename U>
+struct KeyGetter<std::map<T, U> >
+{
+ static const T & get(const typename std::map<T, U>::const_iterator &it)
+ {
+ return it->first;
+ }
+ static const U & value(const typename std::map<T, U>::const_iterator &it)
+ {
+ return it->second;
+ }
+};
+
+
+// We have no built-in defines to check the stdlib features.
+// #define TEST_UNORDERED_MAP
+
+#ifdef TEST_UNORDERED_MAP
+#include <unordered_map>
+typedef std::unordered_map<int, bool> StdUnorderedMap_int_bool;
+
+Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::unordered_map)
+
+Q_DECLARE_METATYPE(StdUnorderedMap_int_bool)
+
+template<typename T, typename U>
+struct KeyGetter<std::unordered_map<T, U> >
+{
+ static const T & get(const typename std::unordered_map<T, U>::const_iterator &it)
+ {
+ return it->first;
+ }
+ static const U & value(const typename std::unordered_map<T, U>::const_iterator &it)
+ {
+ return it->second;
+ }
+};
+#endif
+
+void tst_QVariant::iterateContainerElements()
+{
+#ifdef Q_COMPILER_RANGE_FOR
+
+#define TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) \
+ numSeen = 0; \
+ containerIter = intList.begin(); \
+ for (QVariant v : listIter) { \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, *containerIter)); \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, varList.at(numSeen))); \
+ ++containerIter; \
+ ++numSeen; \
+ } \
+ QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end()));
+
+#else
+
+#define TEST_RANGE_FOR(CONTAINER, VALUE_TYPE)
+
+#endif
+
+#define TEST_SEQUENTIAL_ITERATION(CONTAINER, VALUE_TYPE) \
+ { \
+ int numSeen = 0; \
+ CONTAINER<VALUE_TYPE > intList; \
+ ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 1); \
+ ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 2); \
+ ContainerAPI<CONTAINER<VALUE_TYPE > >::insert(intList, 3); \
+ \
+ QVariant listVariant = QVariant::fromValue(intList); \
+ QVERIFY(listVariant.canConvert<QVariantList>()); \
+ QVariantList varList = listVariant.value<QVariantList>(); \
+ QCOMPARE(varList.size(), (int)std::distance(intList.begin(), intList.end())); \
+ QSequentialIterable listIter = listVariant.value<QSequentialIterable>(); \
+ QCOMPARE(varList.size(), listIter.size()); \
+ \
+ CONTAINER<VALUE_TYPE >::iterator containerIter = intList.begin(); \
+ const CONTAINER<VALUE_TYPE >::iterator containerEnd = intList.end(); \
+ for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen) \
+ { \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(listIter.at(i), *containerIter)); \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(listIter.at(i), varList.at(i))); \
+ } \
+ QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \
+ QCOMPARE(containerIter, containerEnd); \
+ \
+ containerIter = intList.begin(); \
+ numSeen = 0; \
+ Q_FOREACH (const QVariant &v, listIter) { \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, *containerIter)); \
+ QVERIFY(ContainerAPI<CONTAINER<VALUE_TYPE > >::compare(v, varList.at(numSeen))); \
+ ++containerIter; \
+ ++numSeen; \
+ } \
+ QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \
+ TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) \
+ }
+
+ TEST_SEQUENTIAL_ITERATION(QVector, int)
+ TEST_SEQUENTIAL_ITERATION(QVector, QVariant)
+ TEST_SEQUENTIAL_ITERATION(QVector, QString)
+ TEST_SEQUENTIAL_ITERATION(QQueue, int)
+ TEST_SEQUENTIAL_ITERATION(QQueue, QVariant)
+ TEST_SEQUENTIAL_ITERATION(QQueue, QString)
+ TEST_SEQUENTIAL_ITERATION(QList, int)
+ TEST_SEQUENTIAL_ITERATION(QList, QVariant)
+ TEST_SEQUENTIAL_ITERATION(QList, QString)
+ TEST_SEQUENTIAL_ITERATION(QStack, int)
+ TEST_SEQUENTIAL_ITERATION(QStack, QVariant)
+ TEST_SEQUENTIAL_ITERATION(QStack, QString)
+ TEST_SEQUENTIAL_ITERATION(std::vector, int)
+ TEST_SEQUENTIAL_ITERATION(std::vector, QVariant)
+ TEST_SEQUENTIAL_ITERATION(std::vector, QString)
+ TEST_SEQUENTIAL_ITERATION(std::list, int)
+ TEST_SEQUENTIAL_ITERATION(std::list, QVariant)
+ TEST_SEQUENTIAL_ITERATION(std::list, QString)
+
+#ifdef TEST_FORWARD_LIST
+ TEST_SEQUENTIAL_ITERATION(std::forward_list, int)
+ TEST_SEQUENTIAL_ITERATION(std::forward_list, QVariant)
+ TEST_SEQUENTIAL_ITERATION(std::forward_list, QString)
+#endif
+
+ {
+ QVariantList ints;
+ ints << 1 << 2 << 3;
+ QVariant var = QVariant::fromValue(ints);
+ QSequentialIterable iter = var.value<QSequentialIterable>();
+ QSequentialIterable::const_iterator it = iter.begin();
+ QSequentialIterable::const_iterator end = iter.end();
+ QCOMPARE(ints.at(1), *(it + 1));
+ int i = 0;
+ for ( ; it != end; ++it, ++i) {
+ QCOMPARE(ints.at(i), *it);
+ }
+
+ it = iter.begin();
+
+ QVariantList intsCopy;
+ intsCopy << *(it++);
+ intsCopy << *(it++);
+ intsCopy << *(it++);
+ QCOMPARE(ints, intsCopy);
+ }
+
+#define TEST_ASSOCIATIVE_ITERATION(CONTAINER, KEY_TYPE, MAPPED_TYPE) \
+ { \
+ int numSeen = 0; \
+ CONTAINER<KEY_TYPE, MAPPED_TYPE> mapping; \
+ mapping[5] = true; \
+ mapping[15] = false; \
+ \
+ QVariant mappingVariant = QVariant::fromValue(mapping); \
+ QVariantMap varMap = mappingVariant.value<QVariantMap>(); \
+ QVariantMap varHash = mappingVariant.value<QVariantMap>(); \
+ QAssociativeIterable mappingIter = mappingVariant.value<QAssociativeIterable>(); \
+ \
+ CONTAINER<KEY_TYPE, MAPPED_TYPE>::const_iterator containerIter = mapping.begin(); \
+ const CONTAINER<KEY_TYPE, MAPPED_TYPE>::const_iterator containerEnd = mapping.end(); \
+ for ( ; containerIter != containerEnd; ++containerIter, ++numSeen) \
+ { \
+ MAPPED_TYPE expected = KeyGetter<CONTAINER<KEY_TYPE, MAPPED_TYPE> >::value(containerIter); \
+ KEY_TYPE key = KeyGetter<CONTAINER<KEY_TYPE, MAPPED_TYPE> >::get(containerIter); \
+ MAPPED_TYPE actual = mappingIter.value(key).value<MAPPED_TYPE >(); \
+ QCOMPARE(varMap.value(QString::number(key)).value<MAPPED_TYPE>(), expected); \
+ QCOMPARE(varHash.value(QString::number(key)).value<MAPPED_TYPE>(), expected); \
+ QCOMPARE(actual, expected); \
+ } \
+ QCOMPARE(numSeen, (int)std::distance(mapping.begin(), mapping.end())); \
+ QCOMPARE(containerIter, containerEnd); \
+ \
+ }
+
+ TEST_ASSOCIATIVE_ITERATION(QHash, int, bool)
+ TEST_ASSOCIATIVE_ITERATION(QMap, int, bool)
+ TEST_ASSOCIATIVE_ITERATION(std::map, int, bool)
+#ifdef TEST_UNORDERED_MAP
+ TEST_ASSOCIATIVE_ITERATION(std::unordered_map, int, bool)
+#endif
+
+ {
+ QMap<int, QString> mapping;
+ mapping.insert(1, "one");
+ mapping.insert(2, "two");
+ mapping.insert(3, "three");
+ QVariant var = QVariant::fromValue(mapping);
+ QAssociativeIterable iter = var.value<QAssociativeIterable>();
+ QAssociativeIterable::const_iterator it = iter.begin();
+ QAssociativeIterable::const_iterator end = iter.end();
+ QCOMPARE(*(mapping.begin() + 1), (*(it + 1)).toString());
+ int i = 0;
+ for ( ; it != end; ++it, ++i) {
+ QCOMPARE(*(mapping.begin() + i), (*it).toString());
+ }
+
+ QVariantList nums;
+ nums << "one" << "two" << "three";
+
+ it = iter.begin();
+
+ QVariantList numsCopy;
+ numsCopy << *(it++);
+ numsCopy << *(it++);
+ numsCopy << *(it++);
+ QCOMPARE(nums, numsCopy);
+ }
+}
+
+void tst_QVariant::pairElements()
+{
+ typedef QPair<QVariant, QVariant> QVariantPair;
+
+#define TEST_PAIR_ELEMENT_ACCESS(PAIR, T1, T2, VALUE1, VALUE2) \
+ { \
+ PAIR<T1, T2> p(VALUE1, VALUE2); \
+ QVariant v = QVariant::fromValue(p); \
+ \
+ QVERIFY(v.canConvert<QVariantPair>()); \
+ QVariantPair pi = v.value<QVariantPair>(); \
+ QCOMPARE(pi.first, QVariant::fromValue(VALUE1)); \
+ QCOMPARE(pi.second, QVariant::fromValue(VALUE2)); \
+ }
+
+ TEST_PAIR_ELEMENT_ACCESS(QPair, int, int, 4, 5)
+ TEST_PAIR_ELEMENT_ACCESS(std::pair, int, int, 4, 5)
+ TEST_PAIR_ELEMENT_ACCESS(QPair, QString, QString, QStringLiteral("one"), QStringLiteral("two"))
+ TEST_PAIR_ELEMENT_ACCESS(std::pair, QString, QString, QStringLiteral("one"), QStringLiteral("two"))
+ TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, QVariant, 4, 5)
+ TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, QVariant, 4, 5)
+ TEST_PAIR_ELEMENT_ACCESS(QPair, QVariant, int, 41, 15)
+ TEST_PAIR_ELEMENT_ACCESS(std::pair, QVariant, int, 34, 65)
+ TEST_PAIR_ELEMENT_ACCESS(QPair, int, QVariant, 24, 25)
+ TEST_PAIR_ELEMENT_ACCESS(std::pair, int, QVariant, 44, 15)
+}
+
QTEST_MAIN(tst_QVariant)
#include "tst_qvariant.moc"
diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
index 07d3c5c7b8..258f167a20 100644
--- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
+++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp
@@ -766,6 +766,7 @@ void tst_QMimeDatabase::fromThreads()
// sync dtor blocks waiting for finished
}
+#ifndef QT_NO_PROCESS
static bool runUpdateMimeDatabase(const QString &path) // TODO make it a QMimeDatabase method?
{
const QString umdCommand = QString::fromLatin1("update-mime-database");
@@ -799,6 +800,7 @@ static bool waitAndRunUpdateMimeDatabase(const QString &path)
}
return runUpdateMimeDatabase(path);
}
+#endif // !QT_NO_PROCESS
static void checkHasMimeType(const QString &mimeType)
{
@@ -821,6 +823,9 @@ QT_END_NAMESPACE
void tst_QMimeDatabase::installNewGlobalMimeType()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
qmime_secondsBetweenChecks = 0;
QMimeDatabase db;
@@ -862,10 +867,14 @@ void tst_QMimeDatabase::installNewGlobalMimeType()
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
+#endif // !QT_NO_PROCESS
}
void tst_QMimeDatabase::installNewLocalMimeType()
{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
qmime_secondsBetweenChecks = 0;
QMimeDatabase db;
@@ -913,6 +922,7 @@ void tst_QMimeDatabase::installNewLocalMimeType()
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
+#endif
}
QTEST_GUILESS_MAIN(tst_QMimeDatabase)
diff --git a/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp
new file mode 100644
index 0000000000..d5c933e3af
--- /dev/null
+++ b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Intel Corporation
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qplugin.h>
+
+#if QT_POINTER_SIZE == 8
+QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)(0xc0ffeec0ffeeL);
+#else
+QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)0xc0ffee;
+#endif
+QT_PLUGIN_METADATA_SECTION const char message[] = "QTMETADATA";
diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl
new file mode 100755
index 0000000000..ec0dd980a9
--- /dev/null
+++ b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl
@@ -0,0 +1,209 @@
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2013 Intel Corporation.
+## Contact: http://www.qt-project.org/legal
+##
+## This file is the build configuration utility of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## 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.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: 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
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3.0 as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU General Public License version 3.0 requirements will be
+## met: http://www.gnu.org/copyleft/gpl.html.
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+use strict;
+use constant FAT_MAGIC => 0xcafebabe;
+use constant MH_MAGIC => 0xfeedface;
+use constant MH_MAGIC_64 => 0xfeedfacf;
+use constant CPU_TYPE_X86 => 7;
+use constant CPU_TYPE_X86_64 => CPU_TYPE_X86 | 0x01000000;
+use constant CPU_SUBTYPE_I386_ALL => 3;
+use constant MH_DYLIB => 6;
+use constant LC_SEGMENT => 1;
+use constant LC_SEGMENT_64 => 0x19;
+
+my $good = pack("(L7 L2 Z16 L8 Z16 Z16 L9 . L)>",
+ MH_MAGIC, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3
+ 1, # 4: ncmds
+ 4 * (37 - 6), # 5: sizeofcmds
+ 0, # 6: flags
+
+ LC_SEGMENT, # 7: cmd
+ 4 * (37 - 6), # 8: cmdsize
+ '__TEXT', # 9-12: segname
+ 0, # 13: vmaddr
+ 0x1000, # 14: vmsize
+ 0, # 15: fileoff
+ 0x204, # 16: filesize
+ 7, # 17: maxprot (rwx)
+ 5, # 18: initprot (r-x)
+ 1, # 19: nsects
+ 0, # 20: flags
+
+ 'qtmetadata', # 21-24: sectname
+ '__TEXT', # 25-28: segname
+ 0x200, # 29: addr
+ 4, # 30: size
+ 0x200, # 31: offset
+ 2, # 32: align (2^2)
+ 0, # 33: reloff
+ 0, # 34: nreloc
+ 0, # 35: flags
+ 0, # 36: reserved1
+ 0, # 37: reserved2
+
+ 0x200,
+ 0xc0ffee # data
+);
+
+my $good64 = pack("(L8 L2 Z16 Q4 L4 Z16 Z16 Q2 L8 . Q)>",
+ MH_MAGIC_64, CPU_TYPE_X86_64, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3
+ 1, # 4: ncmds
+ 4 * (45 - 7), # 5: sizeofcmds
+ 0, # 6: flags
+ 0, # 7: reserved
+
+ LC_SEGMENT_64, # 8: cmd
+ 4 * (45 - 7), # 9: cmdsize
+ '__TEXT', # 10-13: segname
+ 0, # 14-15: vmaddr
+ 0x1000, # 16-17: vmsize
+ 0, # 18-19: fileoff
+ 0x208, # 20-21: filesize
+ 7, # 22: maxprot (rwx)
+ 5, # 23: initprot (r-x)
+ 1, # 24: nsects
+ 0, # 25: flags
+
+ 'qtmetadata', # 26-29: sectname
+ '__TEXT', # 30-33: segname
+ 0x200, # 34-35: addr
+ 4, # 36-37: size
+ 0x200, # 38: offset
+ 3, # 39: align (2^3)
+ 0, # 40: reloff
+ 0, # 41: nreloc
+ 0, # 42: flags
+ 0, # 43: reserved1
+ 0, # 44: reserved2
+ 0, # 45: reserved3
+
+ 0x200,
+ 0xc0ffeec0ffee # data
+);
+
+my $fat = pack("L>*",
+ FAT_MAGIC, # 1: magic
+ 2, # 2: nfat_arch
+
+ CPU_TYPE_X86, # 3: cputype
+ CPU_SUBTYPE_I386_ALL, # 4: cpusubtype
+ 0x1000, # 5: offset
+ 0x1000, # 6: size
+ 12, # 7: align (2^12)
+
+ CPU_TYPE_X86_64, # 8: cputype
+ CPU_SUBTYPE_I386_ALL, # 9: cpusubtype
+ 0x2000, # 10: offset
+ 0x1000, # 11: size
+ 12, # 12: align (2^12)
+);
+
+my $buffer;
+
+our $badcount = 1;
+sub generate($) {
+ open OUT, ">", "bad$badcount.dylib" or die("Could not open file bad$badcount.dylib: $!\n");
+ binmode OUT;
+ print OUT $_[0];
+ close OUT;
+ ++$badcount;
+}
+
+# Bad file 1-2
+# Except that the cmdsize fields are null
+$buffer = $good;
+vec($buffer, 5, 32) = 0;
+generate $buffer;
+
+$buffer = $good;
+vec($buffer, 8, 32) = 0;
+generate $buffer;
+
+# Bad file 3-4: same as above but 64-bit
+$buffer = $good64;
+vec($buffer, 5, 32) = 0;
+generate $buffer;
+
+$buffer = $good64;
+vec($buffer, 9, 32) = 0;
+generate $buffer;
+
+# Bad file 5-8: same as 1-4, but set cmdsize to bigger than file
+$buffer = $good;
+vec($buffer, 5, 32) = 0x1000;
+generate $buffer;
+
+$buffer = $good;
+vec($buffer, 8, 32) = 0x1000;
+generate $buffer;
+
+$buffer = $good64;
+vec($buffer, 5, 32) = 0x1000;
+generate $buffer;
+
+$buffer = $good64;
+vec($buffer, 9, 32) = 0x1000;
+generate $buffer;
+
+# Bad file 9-10: overflow size+offset
+$buffer = $good;
+vec($buffer, 30, 32) = 0xffffffe0;
+generate $buffer;
+
+$buffer = $good64;
+vec($buffer, 36, 32) = 0xffffffff;
+vec($buffer, 37, 32) = 0xffffffe0;
+generate $buffer;
+
+# Bad file 11: FAT binary with just the header
+generate $fat;
+
+# Bad file 12: FAT binary where the Mach contents don't match the FAT directory
+$buffer = pack("a4096 a4096 a4096", $fat, $good64, $good);
+generate $buffer;
+
+# Bad file 13: FAT binary with overflowing size
+$buffer = pack("a4096 a4096 a4096", $fat, $good, $good64);
+vec($buffer, 5, 32) = 0xfffffffe0;
+vec($buffer, 10, 32) = 0xfffffffe0;
+generate $buffer;
diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro
new file mode 100644
index 0000000000..7acddc22ce
--- /dev/null
+++ b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro
@@ -0,0 +1,56 @@
+TEMPLATE = aux
+OTHER_FILES += \
+ ppcconverter.pl \
+ generate-bad.pl
+
+i386.target = good.i386.dylib
+i386.commands = $(CXX) $(CXXFLAGS) -shared -arch i386 -o $@ -I$$[QT_INSTALL_HEADERS/get] $<
+i386.depends += $$PWD/../fakeplugin.cpp
+x86_64.target = good.x86_64.dylib
+x86_64.commands = $(CXX) $(CXXFLAGS) -shared -arch x86_64 -o $@ -I$$[QT_INSTALL_HEADERS/get] $<
+x86_64.depends += $$PWD/../fakeplugin.cpp
+
+# Current Mac OS X toolchains have no compiler for PPC anymore
+# So we fake it by converting an x86-64 binary to (little-endian!) PPC64
+ppc64.target = good.ppc64.dylib
+ppc64.commands = $$PWD/ppcconverter.pl $< $@
+ppc64.depends = x86_64 $$PWD/ppcconverter.pl
+
+# Generate a fat binary with three architectures
+fat_all.target = good.fat.all.dylib
+fat_all.commands = lipo -create -output $@ \
+ -arch ppc64 $$ppc64.target \
+ -arch i386 $$i386.target \
+ -arch x86_64 $$x86_64.target
+fat_all.depends += i386 x86_64 ppc64
+
+fat_no_i386.target = good.fat.no-i386.dylib
+fat_no_i386.commands = lipo -create -output $@ -arch x86_64 $$x86_64.target -arch ppc64 $$ppc64.target
+fat_no_i386.depends += x86_64 ppc64
+
+fat_no_x86_64.target = good.fat.no-x86_64.dylib
+fat_no_x86_64.commands = lipo -create -output $@ -arch i386 $$i386.target -arch ppc64 $$ppc64.target
+fat_no_x86_64.depends += i386 ppc64
+
+fat_stub_i386.target = good.fat.stub-i386.dylib
+fat_stub_i386.commands = lipo -create -output $@ -arch ppc64 $$ppc64.target -arch_blank i386
+fat_stub_i386.depends += x86_64 ppc64
+
+fat_stub_x86_64.target = good.fat.stub-x86_64.dylib
+fat_stub_x86_64.commands = lipo -create -output $@ -arch ppc64 $$ppc64.target -arch_blank x86_64
+fat_stub_x86_64.depends += i386 ppc64
+
+bad.commands = $$PWD/generate-bad.pl
+bad.depends += $$PWD/generate-bad.pl
+
+MYTARGETS = $$fat_all.depends fat_all fat_no_x86_64 fat_no_i386 \
+ fat_stub_i386 fat_stub_x86_64 bad
+all.depends += $$MYTARGETS
+QMAKE_EXTRA_TARGETS += $$MYTARGETS all
+
+QMAKE_CLEAN += $$i386.target $$x86_64.target $$ppc64.target $$fat_all.target \
+ $$fat_no_i386.target $$fat_no_x86_64.target \
+ $$fat_stub_i386.target $$fat_stub_x86_64.target \
+ "bad*.dylib"
+
+
diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl
new file mode 100755
index 0000000000..86943161b7
--- /dev/null
+++ b/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2013 Intel Corporation.
+## Contact: http://www.qt-project.org/legal
+##
+## This file is the build configuration utility of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## 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.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: 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
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3.0 as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU General Public License version 3.0 requirements will be
+## met: http://www.gnu.org/copyleft/gpl.html.
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+# Changes the Mach-O file type header to PowerPC.
+#
+# The header is (from mach-o/loader.h):
+# struct mach_header {
+# uint32_t magic; /* mach magic number identifier */
+# cpu_type_t cputype; /* cpu specifier */
+# cpu_subtype_t cpusubtype; /* machine specifier */
+# uint32_t filetype; /* type of file */
+# uint32_t ncmds; /* number of load commands */
+# uint32_t sizeofcmds; /* the size of all the load commands */
+# uint32_t flags; /* flags */
+# };
+#
+# The 64-bit header is identical in the first three fields, except for a different
+# magic number. We will not touch the magic number, we'll just reset the cputype
+# field to the PowerPC type and the subtype field to zero.
+#
+# We will not change the file's endianness. That means we might create a little-endian
+# PowerPC binary, which could not be run in real life.
+#
+# We will also not change the 64-bit ABI flag, which is found in the cputype's high
+# byte. That means we'll create a PPC64 binary if fed a 64-bit input.
+#
+use strict;
+use constant MH_MAGIC => 0xfeedface;
+use constant MH_CIGAM => 0xcefaedfe;
+use constant MH_MAGIC_64 => 0xfeedfacf;
+use constant MH_CIGAM_64 => 0xcffaedfe;
+use constant CPU_TYPE_POWERPC => 18;
+use constant CPU_SUBTYPE_POWERPC_ALL => 0;
+
+my $infile = shift @ARGV or die("Missing input filename");
+my $outfile = shift @ARGV or die("Missing output filename");
+
+open IN, "<$infile" or die("Can't open $infile for reading: $!\n");
+open OUT, ">$outfile" or die("Can't open $outfile for writing: $!\n");
+
+binmode IN;
+binmode OUT;
+
+# Read the first 12 bytes, which includes the interesting fields of the header
+my $buffer;
+read(IN, $buffer, 12);
+
+my $magic = vec($buffer, 0, 32);
+if ($magic == MH_MAGIC || $magic == MH_MAGIC_64) {
+ # Big endian
+ # The low byte of cputype is at offset 7
+ vec($buffer, 7, 8) = CPU_TYPE_POWERPC;
+} elsif ($magic == MH_CIGAM || $magic == MH_CIGAM_64) {
+ # Little endian
+ # The low byte of cpytype is at offset 4
+ vec($buffer, 4, 8) = CPU_TYPE_POWERPC;
+} else {
+ $magic = '';
+ $magic .= sprintf("%02X ", $_) for unpack("CCCC", $buffer);
+ die("Invalid input. Unknown magic $magic\n");
+}
+vec($buffer, 2, 32) = CPU_SUBTYPE_POWERPC_ALL;
+
+print OUT $buffer;
+
+# Copy the rest
+while (!eof(IN)) {
+ read(IN, $buffer, 4096) and
+ print OUT $buffer or
+ die("Problem copying: $!\n");
+}
+close(IN);
+close(OUT);
diff --git a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro b/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro
index 0cba19887e..8d117793bf 100644
--- a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro
+++ b/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro
@@ -5,6 +5,7 @@ SUBDIRS = lib \
theplugin \
tst
!win32: !mac: SUBDIRS += almostplugin
+macx-*: SUBDIRS += machtest
TARGET = tst_qpluginloader
# no special install rule for subdir
diff --git a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro
index a7a9661a54..3894c90ae3 100644
--- a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro
+++ b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro
@@ -2,7 +2,8 @@ CONFIG += testcase
CONFIG += parallel_test
TARGET = ../tst_qpluginloader
QT = core testlib
-SOURCES = ../tst_qpluginloader.cpp
+contains(QT_CONFIG, private_tests): QT += core-private
+SOURCES = ../tst_qpluginloader.cpp ../fakeplugin.cpp
HEADERS = ../theplugin/plugininterface.h
CONFIG -= app_bundle
@@ -14,5 +15,5 @@ win32 {
}
}
-TESTDATA += ../elftest
+TESTDATA += ../elftest ../machtest
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
index cef4f53101..351e3a23e0 100644
--- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
+++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
@@ -44,6 +44,10 @@
#include <qpluginloader.h>
#include "theplugin/plugininterface.h"
+#if defined(QT_BUILD_INTERNAL) && defined(Q_OF_MACH_O)
+# include <QtCore/private/qmachparser_p.h>
+#endif
+
// Helper macros to let us know if some suffixes are valid
#define bundle_VALID false
#define dylib_VALID false
@@ -118,6 +122,8 @@ private slots:
void deleteinstanceOnUnload();
void loadDebugObj();
void loadCorruptElf();
+ void loadMachO_data();
+ void loadMachO();
#if defined (Q_OS_UNIX)
void loadGarbage();
#endif
@@ -311,6 +317,78 @@ void tst_QPluginLoader::loadCorruptElf()
#endif
}
+void tst_QPluginLoader::loadMachO_data()
+{
+#ifdef Q_OF_MACH_O
+ QTest::addColumn<int>("parseResult");
+
+ QTest::newRow("/dev/null") << int(QMachOParser::NotSuitable);
+ QTest::newRow("elftest/debugobj.so") << int(QMachOParser::NotSuitable);
+ QTest::newRow("tst_qpluginloader.cpp") << int(QMachOParser::NotSuitable);
+ QTest::newRow("tst_qpluginloader") << int(QMachOParser::NotSuitable);
+
+# ifdef Q_PROCESSOR_X86_64
+ QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::QtMetaDataSection);
+ QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::NotSuitable);
+ QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::NotSuitable);
+ QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::QtMetaDataSection);
+# elif defined(Q_PROCESSOR_X86_32)
+ QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::QtMetaDataSection);
+ QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::NotSuitable);
+ QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::NotSuitable);
+ QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::QtMetaDataSection);
+# endif
+# ifndef Q_PROCESSOR_POWER_64
+ QTest::newRow("machtest/good.ppc64.dylib") << int(QMachOParser::NotSuitable);
+# endif
+
+ QTest::newRow("machtest/good.fat.all.dylib") << int(QMachOParser::QtMetaDataSection);
+ QTest::newRow("machtest/good.fat.stub-x86_64.dylib") << int(QMachOParser::NotSuitable);
+ QTest::newRow("machtest/good.fat.stub-i386.dylib") << int(QMachOParser::NotSuitable);
+
+ QDir d(QFINDTESTDATA("machtest"));
+ QStringList badlist = d.entryList(QStringList() << "bad*.dylib");
+ foreach (const QString &bad, badlist)
+ QTest::newRow(qPrintable("machtest/" + bad)) << int(QMachOParser::NotSuitable);
+#endif
+}
+
+void tst_QPluginLoader::loadMachO()
+{
+#ifdef Q_OF_MACH_O
+ QFile f(QFINDTESTDATA(QTest::currentDataTag()));
+ QVERIFY(f.open(QIODevice::ReadOnly));
+ QByteArray data = f.readAll();
+
+ long pos;
+ ulong len;
+ QString errorString;
+ int r = QMachOParser::parse(data.constData(), data.size(), f.fileName(), &errorString, &pos, &len);
+
+ QFETCH(int, parseResult);
+ QCOMPARE(r, parseResult);
+
+ if (r == QMachOParser::NotSuitable)
+ return;
+
+ QVERIFY(pos > 0);
+ QVERIFY(len >= sizeof(void*));
+ QVERIFY(pos + long(len) < data.size());
+ QCOMPARE(pos & (sizeof(void*) - 1), 0UL);
+
+ void *value = *(void**)(data.constData() + pos);
+ QCOMPARE(value, sizeof(void*) > 4 ? (void*)(0xc0ffeec0ffeeL) : (void*)0xc0ffee);
+
+ // now that we know it's valid, let's try to make it invalid
+ ulong offeredlen = pos;
+ do {
+ --offeredlen;
+ r = QMachOParser::parse(data.constData(), offeredlen, f.fileName(), &errorString, &pos, &len);
+ QVERIFY2(r == QMachOParser::NotSuitable, qPrintable(QString("Failed at size 0x%1").arg(offeredlen, 0, 16)));
+ } while (offeredlen);
+#endif
+}
+
#if defined (Q_OS_UNIX)
void tst_QPluginLoader::loadGarbage()
{
diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
index 1ee628dde5..5cc0e5bdb4 100644
--- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp
+++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
@@ -106,6 +106,8 @@ private slots:
void customEventDispatcher();
+ void requestTermination();
+
#ifndef Q_OS_WINCE
void stressTest();
#endif
@@ -1345,5 +1347,43 @@ void tst_QThread::quitLock()
QVERIFY(exitThreadCalled);
}
+class StopableJob : public QObject
+{
+ Q_OBJECT
+public:
+ StopableJob (QSemaphore &sem) : sem(sem) {}
+ QSemaphore &sem;
+public Q_SLOTS:
+ void run() {
+ sem.release();
+ while (!thread()->isInterruptionRequested())
+ QTest::qSleep(10);
+ sem.release();
+ Q_EMIT finished();
+ }
+Q_SIGNALS:
+ void finished();
+};
+
+void tst_QThread::requestTermination()
+{
+ QThread thread;
+ QVERIFY(!thread.isInterruptionRequested());
+ QSemaphore sem;
+ StopableJob *j = new StopableJob(sem);
+ j->moveToThread(&thread);
+ connect(&thread, &QThread::started, j, &StopableJob::run);
+ connect(j, &StopableJob::finished, &thread, &QThread::quit, Qt::DirectConnection);
+ connect(&thread, &QThread::finished, j, &QObject::deleteLater);
+ thread.start();
+ QVERIFY(!thread.isInterruptionRequested());
+ sem.acquire();
+ QVERIFY(!thread.wait(1000));
+ thread.requestInterruption();
+ sem.acquire();
+ QVERIFY(thread.wait(1000));
+ QVERIFY(!thread.isInterruptionRequested());
+}
+
QTEST_MAIN(tst_QThread)
#include "tst_qthread.moc"
diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
index 3c0e132a0a..4a9932798c 100644
--- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
+++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp
@@ -90,6 +90,7 @@ private slots:
void reserveThread();
void releaseThread_data();
void releaseThread();
+ void reserveAndStart();
void start();
void tryStart();
void tryStartPeakThreadCount();
@@ -97,6 +98,7 @@ private slots:
void priorityStart_data();
void priorityStart();
void waitForDone();
+ void clear();
void waitForDoneTimeout();
void destroyingWaitsForTasksToFinish();
void stressTest();
@@ -214,22 +216,22 @@ void tst_QThreadPool::waitcomplete()
QCOMPARE(testFunctionCount, runs);
}
-volatile bool ran;
+QAtomicInt ran; // bool
class TestTask : public QRunnable
{
public:
void run()
{
- ran = true;
+ ran.store(true);
}
};
void tst_QThreadPool::runTask()
{
QThreadPool manager;
- ran = false;
+ ran.store(false);
manager.start(new TestTask());
- QTRY_VERIFY(ran);
+ QTRY_VERIFY(ran.load());
}
/*
@@ -237,19 +239,19 @@ void tst_QThreadPool::runTask()
*/
void tst_QThreadPool::singleton()
{
- ran = false;
+ ran.store(false);
QThreadPool::globalInstance()->start(new TestTask());
- QTRY_VERIFY(ran);
+ QTRY_VERIFY(ran.load());
}
-int *value = 0;
+QAtomicInt *value = 0;
class IntAccessor : public QRunnable
{
public:
void run()
{
for (int i = 0; i < 100; ++i) {
- ++(*value);
+ value->ref();
QTest::qSleep(1);
}
}
@@ -261,7 +263,7 @@ public:
*/
void tst_QThreadPool::destruction()
{
- value = new int;
+ value = new QAtomicInt;
QThreadPool *threadManager = new QThreadPool();
threadManager->start(new IntAccessor());
threadManager->start(new IntAccessor());
@@ -629,6 +631,65 @@ void tst_QThreadPool::releaseThread()
threadpool->setMaxThreadCount(savedLimit);
}
+void tst_QThreadPool::reserveAndStart() // QTBUG-21051
+{
+ class WaitingTask : public QRunnable
+ {
+ public:
+ QAtomicInt count;
+ QSemaphore waitForStarted;
+ QSemaphore waitBeforeDone;
+
+ WaitingTask() { setAutoDelete(false); }
+
+ void run()
+ {
+ count.ref();
+ waitForStarted.release();
+ waitBeforeDone.acquire();
+ }
+ };
+
+ // Set up
+ QThreadPool *threadpool = QThreadPool::globalInstance();
+ int savedLimit = threadpool->maxThreadCount();
+ threadpool->setMaxThreadCount(1);
+ QCOMPARE(threadpool->activeThreadCount(), 0);
+
+ // reserve
+ threadpool->reserveThread();
+ QCOMPARE(threadpool->activeThreadCount(), 1);
+
+ // start a task, to get a running thread
+ WaitingTask *task = new WaitingTask;
+ threadpool->start(task);
+ QCOMPARE(threadpool->activeThreadCount(), 2);
+ task->waitForStarted.acquire();
+ task->waitBeforeDone.release();
+ QTRY_COMPARE(task->count.load(), 1);
+ QTRY_COMPARE(threadpool->activeThreadCount(), 1);
+
+ // now the thread is waiting, but tryStart() will fail since activeThreadCount() >= maxThreadCount()
+ QVERIFY(!threadpool->tryStart(task));
+ QTRY_COMPARE(threadpool->activeThreadCount(), 1);
+
+ // start() will therefore do a failing tryStart(), followed by enqueueTask()
+ // which will actually wake up the waiting thread.
+ threadpool->start(task);
+ QTRY_COMPARE(threadpool->activeThreadCount(), 2);
+ task->waitForStarted.acquire();
+ task->waitBeforeDone.release();
+ QTRY_COMPARE(task->count.load(), 2);
+ QTRY_COMPARE(threadpool->activeThreadCount(), 1);
+
+ threadpool->releaseThread();
+ QTRY_COMPARE(threadpool->activeThreadCount(), 0);
+
+ delete task;
+
+ threadpool->setMaxThreadCount(savedLimit);
+}
+
QAtomicInt count;
class CountingRunnable : public QRunnable
{
@@ -681,8 +742,8 @@ void tst_QThreadPool::tryStart()
}
QMutex mutex;
-int activeThreads = 0;
-int peakActiveThreads = 0;
+QAtomicInt activeThreads;
+QAtomicInt peakActiveThreads;
void tst_QThreadPool::tryStartPeakThreadCount()
{
class CounterTask : public QRunnable
@@ -694,14 +755,14 @@ void tst_QThreadPool::tryStartPeakThreadCount()
{
{
QMutexLocker lock(&mutex);
- ++activeThreads;
- peakActiveThreads = qMax(peakActiveThreads, activeThreads);
+ activeThreads.ref();
+ peakActiveThreads.store(qMax(peakActiveThreads.load(), activeThreads.load()));
}
QTest::qWait(100);
{
QMutexLocker lock(&mutex);
- --activeThreads;
+ activeThreads.deref();
}
}
};
@@ -713,13 +774,13 @@ void tst_QThreadPool::tryStartPeakThreadCount()
if (threadPool.tryStart(&task) == false)
QTest::qWait(10);
}
- QCOMPARE(peakActiveThreads, QThread::idealThreadCount());
+ QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount());
for (int i = 0; i < 20; ++i) {
if (threadPool.tryStart(&task) == false)
QTest::qWait(10);
}
- QCOMPARE(peakActiveThreads, QThread::idealThreadCount());
+ QCOMPARE(peakActiveThreads.load(), QThread::idealThreadCount());
}
void tst_QThreadPool::tryStartCount()
@@ -855,6 +916,34 @@ void tst_QThreadPool::waitForDoneTimeout()
QVERIFY(threadPool.waitForDone(400));
}
+void tst_QThreadPool::clear()
+{
+ QSemaphore sem(0);
+ class BlockingRunnable : public QRunnable
+ {
+ public:
+ QSemaphore & sem;
+ BlockingRunnable(QSemaphore & sem) : sem(sem){}
+ void run()
+ {
+ sem.acquire();
+ count.ref();
+ }
+ };
+
+ QThreadPool threadPool;
+ threadPool.setMaxThreadCount(10);
+ int runs = 2 * threadPool.maxThreadCount();
+ count.store(0);
+ for (int i = 0; i <= runs; i++) {
+ threadPool.start(new BlockingRunnable(sem));
+ }
+ threadPool.clear();
+ sem.release(threadPool.maxThreadCount());
+ threadPool.waitForDone();
+ QCOMPARE(count.load(), threadPool.maxThreadCount());
+}
+
void tst_QThreadPool::destroyingWaitsForTasksToFinish()
{
QTime total, pass;
diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
index 72bf5c58ca..144bc62b1b 100644
--- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
+++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
@@ -44,6 +44,7 @@
#include <iostream>
#include <iomanip>
#include <sstream>
+#include <iterator>
#include <algorithm>
#include <qalgorithms.h>
#include <QStringList>
@@ -78,10 +79,22 @@ private slots:
void qCountContainer() const;
void binaryFindOnLargeContainer() const;
-#if Q_TEST_PERFORMANCE
+ void popCount08_data() { popCount_data_impl(sizeof(quint8 )); }
+ void popCount16_data() { popCount_data_impl(sizeof(quint16)); }
+ void popCount32_data() { popCount_data_impl(sizeof(quint32)); }
+ void popCount64_data() { popCount_data_impl(sizeof(quint64)); }
+ void popCount08() { popCount_impl<quint8 >(); }
+ void popCount16() { popCount_impl<quint16>(); }
+ void popCount32() { popCount_impl<quint32>(); }
+ void popCount64() { popCount_impl<quint64>(); }
+
private:
+#if Q_TEST_PERFORMANCE
void performance();
#endif
+ void popCount_data_impl(size_t sizeof_T_Int);
+ template <typename T_Int>
+ void popCount_impl();
};
class TestInt
@@ -834,6 +847,12 @@ void tst_QAlgorithms::qCountContainer() const
class RAI
{
public:
+ typedef int difference_type;
+ typedef int value_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef int *pointer;
+ typedef int &reference;
+
RAI(int searched = 5, int hidePos = 4, int len = 10)
: curPos_(0)
, length_(len)
@@ -1007,6 +1026,72 @@ void tst_QAlgorithms::binaryFindOnLargeContainer() const
QCOMPARE(foundIt.pos(), 1073987655);
}
+// alternative implementation of qPopulationCount for comparison:
+static const uint bitsSetInNibble[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+};
+Q_STATIC_ASSERT(sizeof bitsSetInNibble / sizeof *bitsSetInNibble == 16);
+
+static Q_DECL_CONSTEXPR uint bitsSetInByte(quint8 byte)
+{
+ return bitsSetInNibble[byte & 0xF] + bitsSetInNibble[byte >> 4];
+}
+static Q_DECL_CONSTEXPR uint bitsSetInShort(quint16 word)
+{
+ return bitsSetInByte(word & 0xFF) + bitsSetInByte(word >> 8);
+}
+static Q_DECL_CONSTEXPR uint bitsSetInInt(quint32 word)
+{
+ return bitsSetInShort(word & 0xFFFF) + bitsSetInShort(word >> 16);
+}
+static Q_DECL_CONSTEXPR uint bitsSetInInt64(quint64 word)
+{
+ return bitsSetInInt(word & 0xFFFFFFFF) + bitsSetInInt(word >> 32);
+}
+
+
+void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int)
+{
+ using namespace QTest;
+ addColumn<quint64>("input");
+ addColumn<uint>("expected");
+
+ for (uint i = 0; i < UCHAR_MAX; ++i) {
+ const uchar byte = static_cast<uchar>(i);
+ const uint bits = bitsSetInByte(byte);
+ const quint64 value = static_cast<quint64>(byte);
+ const quint64 input = value << ((i % sizeof_T_Int) * 8U);
+ newRow(qPrintable(QString().sprintf("0x%016llx", input))) << input << bits;
+ }
+
+ // and some random ones:
+ if (sizeof_T_Int >= 8)
+ for (size_t i = 0; i < 1000; ++i) {
+ const quint64 input = quint64(qrand()) << 32 | quint32(qrand());
+ newRow(qPrintable(QString().sprintf("0x%016llx", input))) << input << bitsSetInInt64(input);
+ }
+ else if (sizeof_T_Int >= 2)
+ for (size_t i = 0; i < 1000 ; ++i) {
+ const quint32 input = qrand();
+ if (sizeof_T_Int >= 4)
+ newRow(qPrintable(QString().sprintf("0x%08x", input))) << quint64(input) << bitsSetInInt(input);
+ else
+ newRow(qPrintable(QString().sprintf("0x%04x", quint16(input & 0xFFFF)))) << quint64(input & 0xFFFF) << bitsSetInShort(input & 0xFFFF);
+ }
+}
+
+template <typename T_Int>
+void tst_QAlgorithms::popCount_impl()
+{
+ QFETCH(quint64, input);
+ QFETCH(uint, expected);
+
+ const T_Int value = static_cast<T_Int>(input);
+
+ QCOMPARE(qPopulationCount(value), expected);
+}
+
QTEST_APPLESS_MAIN(tst_QAlgorithms)
#include "tst_qalgorithms.moc"
diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
index 933807c525..d7cc92e6c0 100644
--- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp
@@ -614,6 +614,24 @@ void tst_QByteArray::base64()
QByteArray arr64 = rawdata.toBase64();
QCOMPARE(arr64, base64);
+
+ arr64 = rawdata.toBase64(QByteArray::Base64Encoding);
+ QCOMPARE(arr64, base64);
+
+ QByteArray base64noequals = base64;
+ base64noequals.replace('=', "");
+ arr64 = rawdata.toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals);
+ QCOMPARE(arr64, base64noequals);
+
+ QByteArray base64url = base64;
+ base64url.replace('/', '_').replace('+', '-');
+ arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding);
+ QCOMPARE(arr64, base64url);
+
+ QByteArray base64urlnoequals = base64url;
+ base64urlnoequals.replace('=', "");
+ arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
+ QCOMPARE(arr64, base64urlnoequals);
}
//different from the previous test as the input are invalid
@@ -662,6 +680,23 @@ void tst_QByteArray::fromBase64()
QByteArray arr = QByteArray::fromBase64(base64);
QCOMPARE(arr, rawdata);
+
+ arr = QByteArray::fromBase64(base64, QByteArray::Base64Encoding);
+ QCOMPARE(arr, rawdata);
+
+ // try "base64url" encoding
+ QByteArray base64url = base64;
+ base64url.replace('/', '_').replace('+', '-');
+ arr = QByteArray::fromBase64(base64url, QByteArray::Base64UrlEncoding);
+ QCOMPARE(arr, rawdata);
+
+ if (base64 != base64url) {
+ // check that the invalid decodings fail
+ arr = QByteArray::fromBase64(base64, QByteArray::Base64UrlEncoding);
+ QVERIFY(arr != rawdata);
+ arr = QByteArray::fromBase64(base64url, QByteArray::Base64Encoding);
+ QVERIFY(arr != rawdata);
+ }
}
void tst_QByteArray::qvsnprintf()
diff --git a/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro b/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro
new file mode 100644
index 0000000000..a9aedc4c0d
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += tst_qcommandlineparser.pro testhelper/qcommandlineparser_test_helper.pro
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
new file mode 100644
index 0000000000..07f8ddfc8e
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 David Faure <faure@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QCoreApplication>
+#include <QCommandLineParser>
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ app.setApplicationVersion("1.0");
+
+ // Test for QCoreApplication::arguments()
+ const QStringList incomingArgs = QCoreApplication::arguments();
+ for (int i = 0; i < argc; ++i) {
+ if (incomingArgs.at(i) != QLatin1String(argv[i]))
+ qDebug() << "ERROR: arguments[" << i << "] was" << incomingArgs.at(i) << "expected" << argv[i];
+ }
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription("Test helper");
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument("parsingMode", "The parsing mode to test.");
+ parser.addPositionalArgument("command", "The command to execute.");
+ parser.addOption(QCommandLineOption("load", "Load file from URL.", "url"));
+ parser.addOption(QCommandLineOption(QStringList() << "o" << "output", "Set output file.", "file"));
+ parser.addOption(QCommandLineOption("D", "Define macro.", "key=value"));
+
+ // An option with a longer description, to test wrapping
+ QCommandLineOption noImplicitIncludesOption(QStringList() << QStringLiteral("n") << QStringLiteral("no-implicit-includes"));
+ noImplicitIncludesOption.setDescription(QStringLiteral("Disable automatic generation of implicit #include-directives."));
+ parser.addOption(noImplicitIncludesOption);
+
+ // This program supports different options depending on the "command" (first argument).
+ // Call parse() to find out the positional arguments.
+ parser.parse(QCoreApplication::arguments());
+
+ QStringList args = parser.positionalArguments();
+ if (args.isEmpty())
+ parser.showHelp(1);
+ parser.setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode(args.takeFirst().toInt()));
+ const QString command = args.isEmpty() ? QString() : args.first();
+ if (command == "resize") {
+ parser.clearPositionalArguments();
+ parser.addPositionalArgument("resize", "Resize the object to a new size.", "resize [resize_options]");
+ parser.addOption(QCommandLineOption("size", "New size.", "size"));
+ parser.process(app);
+ const QString size = parser.value("size");
+ printf("Resizing %s to %s and saving to %s\n", qPrintable(parser.value("load")), qPrintable(size), qPrintable(parser.value("o")));
+ } else {
+ // Call process again, to handle unknown options this time.
+ parser.process(app);
+ }
+
+ printf("Positional arguments: %s\n", qPrintable(parser.positionalArguments().join(",")));
+ printf("Macros: %s\n", qPrintable(parser.values("D").join(",")));
+
+ return 0;
+}
+
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro
new file mode 100644
index 0000000000..dce1ac0d37
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro
@@ -0,0 +1,6 @@
+CONFIG += console
+CONFIG -= app_bundle
+QT = core
+DESTDIR = ./
+
+SOURCES += qcommandlineparser_test_helper.cpp
diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
new file mode 100644
index 0000000000..9219ff72df
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 David Faure <faure@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/QCommandLineParser>
+
+Q_DECLARE_METATYPE(char**)
+
+class tst_QCommandLineParser : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void parsingModes_data();
+
+ // In-process tests
+ void testInvalidOptions();
+ void testPositionalArguments();
+ void testBooleanOption_data();
+ void testBooleanOption();
+ void testMultipleNames_data();
+ void testMultipleNames();
+ void testSingleValueOption_data();
+ void testSingleValueOption();
+ void testValueNotSet();
+ void testMultipleValuesOption();
+ void testUnknownOptionErrorHandling_data();
+ void testUnknownOptionErrorHandling();
+ void testDoubleDash_data();
+ void testDoubleDash();
+ void testProcessNotCalled();
+ void testEmptyArgsList();
+ void testMissingOptionValue();
+ void testStdinArgument_data();
+ void testStdinArgument();
+ void testSingleDashWordOptionModes_data();
+ void testSingleDashWordOptionModes();
+
+ // QProcess-based tests using qcommandlineparser_test_helper
+ void testVersionOption();
+ void testHelpOption_data();
+ void testHelpOption();
+ void testQuoteEscaping();
+};
+
+static char *empty_argv[] = { const_cast<char*>("tst_qcommandlineparser") };
+static int empty_argc = 1;
+
+Q_DECLARE_METATYPE(QCommandLineParser::SingleDashWordOptionMode)
+
+void tst_QCommandLineParser::parsingModes_data()
+{
+ QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
+
+ QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions;
+ QTest::newRow("implicitlylong") << QCommandLineParser::ParseAsLongOptions;
+}
+
+void tst_QCommandLineParser::testInvalidOptions()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineOption: Option names cannot start with a '-'");
+ parser.addOption(QCommandLineOption(QStringLiteral("-v"), QStringLiteral("Displays version information.")));
+}
+
+void tst_QCommandLineParser::testPositionalArguments()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "file.txt"));
+ QCOMPARE(parser.positionalArguments(), QStringList() << QStringLiteral("file.txt"));
+}
+
+void tst_QCommandLineParser::testBooleanOption_data()
+{
+ QTest::addColumn<QStringList>("args");
+ QTest::addColumn<QStringList>("expectedOptionNames");
+ QTest::addColumn<bool>("expectedIsSet");
+
+ QTest::newRow("set") << (QStringList() << "tst_qcommandlineparser" << "-b") << (QStringList() << "b") << true;
+ QTest::newRow("unset") << (QStringList() << "tst_qcommandlineparser") << QStringList() << false;
+}
+
+void tst_QCommandLineParser::testBooleanOption()
+{
+ QFETCH(QStringList, args);
+ QFETCH(QStringList, expectedOptionNames);
+ QFETCH(bool, expectedIsSet);
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"), QStringLiteral("a boolean option"))));
+ QVERIFY(parser.parse(args));
+ QCOMPARE(parser.optionNames(), expectedOptionNames);
+ QCOMPARE(parser.isSet("b"), expectedIsSet);
+ QCOMPARE(parser.values("b"), QStringList());
+ QCOMPARE(parser.positionalArguments(), QStringList());
+ // Should warn on typos
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not defined: \"c\"");
+ QVERIFY(!parser.isSet("c"));
+}
+
+void tst_QCommandLineParser::testMultipleNames_data()
+{
+ QTest::addColumn<QStringList>("args");
+ QTest::addColumn<QStringList>("expectedOptionNames");
+
+ QTest::newRow("short") << (QStringList() << "tst_qcommandlineparser" << "-v") << (QStringList() << "v");
+ QTest::newRow("long") << (QStringList() << "tst_qcommandlineparser" << "--version") << (QStringList() << "version");
+ QTest::newRow("not_set") << (QStringList() << "tst_qcommandlineparser") << QStringList();
+}
+
+void tst_QCommandLineParser::testMultipleNames()
+{
+ QFETCH(QStringList, args);
+ QFETCH(QStringList, expectedOptionNames);
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineOption option(QStringList() << "v" << "version", QStringLiteral("Show version information"));
+ QCOMPARE(option.names(), QStringList() << "v" << "version");
+ QCommandLineParser parser;
+ QVERIFY(parser.addOption(option));
+ QVERIFY(parser.parse(args));
+ QCOMPARE(parser.optionNames(), expectedOptionNames);
+ const bool expectedIsSet = !expectedOptionNames.isEmpty();
+ QCOMPARE(parser.isSet("v"), expectedIsSet);
+ QCOMPARE(parser.isSet("version"), expectedIsSet);
+}
+
+void tst_QCommandLineParser::testSingleValueOption_data()
+{
+ QTest::addColumn<QStringList>("args");
+ QTest::addColumn<QStringList>("defaults");
+ QTest::addColumn<bool>("expectedIsSet");
+
+ QTest::newRow("short") << (QStringList() << "tst" << "-s" << "oxygen") << QStringList() << true;
+ QTest::newRow("long") << (QStringList() << "tst" << "--style" << "oxygen") << QStringList() << true;
+ QTest::newRow("longequal") << (QStringList() << "tst" << "--style=oxygen") << QStringList() << true;
+ QTest::newRow("default") << (QStringList() << "tst") << (QStringList() << "oxygen") << false;
+}
+
+void tst_QCommandLineParser::testSingleValueOption()
+{
+ QFETCH(QStringList, args);
+ QFETCH(QStringList, defaults);
+ QFETCH(bool, expectedIsSet);
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QCommandLineOption option(QStringList() << "s" << "style", QStringLiteral("style name"), "styleName");
+ option.setDefaultValues(defaults);
+ QVERIFY(parser.addOption(option));
+ for (int mode = 0; mode < 2; ++mode) {
+ parser.setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode(mode));
+ QVERIFY(parser.parse(args));
+ QCOMPARE(parser.isSet("s"), expectedIsSet);
+ QCOMPARE(parser.isSet("style"), expectedIsSet);
+ QCOMPARE(parser.isSet(option), expectedIsSet);
+ QCOMPARE(parser.value("s"), QString("oxygen"));
+ QCOMPARE(parser.value("style"), QString("oxygen"));
+ QCOMPARE(parser.values("s"), QStringList() << "oxygen");
+ QCOMPARE(parser.values("style"), QStringList() << "oxygen");
+ QCOMPARE(parser.values(option), QStringList() << "oxygen");
+ QCOMPARE(parser.positionalArguments(), QStringList());
+ }
+ // Should warn on typos
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not defined: \"c\"");
+ QVERIFY(parser.values("c").isEmpty());
+}
+
+void tst_QCommandLineParser::testValueNotSet()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ // Not set, no default value
+ QCommandLineParser parser;
+ QCommandLineOption option(QStringList() << "s" << "style", QStringLiteral("style name"));
+ option.setValueName("styleName");
+ QVERIFY(parser.addOption(option));
+ QVERIFY(parser.parse(QStringList() << "tst"));
+ QCOMPARE(parser.optionNames(), QStringList());
+ QVERIFY(!parser.isSet("s"));
+ QVERIFY(!parser.isSet("style"));
+ QCOMPARE(parser.value("s"), QString());
+ QCOMPARE(parser.value("style"), QString());
+ QCOMPARE(parser.values("s"), QStringList());
+ QCOMPARE(parser.values("style"), QStringList());
+}
+
+void tst_QCommandLineParser::testMultipleValuesOption()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineOption option(QStringLiteral("param"), QStringLiteral("Pass parameter to the backend."));
+ option.setValueName("key=value");
+ QCommandLineParser parser;
+ QVERIFY(parser.addOption(option));
+ {
+ QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1"));
+ QVERIFY(parser.isSet("param"));
+ QCOMPARE(parser.values("param"), QStringList() << "key1=value1");
+ QCOMPARE(parser.value("param"), QString("key1=value1"));
+ }
+ {
+ QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1" << "--param" << "key2=value2"));
+ QVERIFY(parser.isSet("param"));
+ QCOMPARE(parser.values("param"), QStringList() << "key1=value1" << "key2=value2");
+ QCOMPARE(parser.value("param"), QString("key2=value2"));
+ }
+
+ QString expected =
+ "Usage: tst_qcommandlineparser [options]\n"
+ "\n"
+ "Options:\n"
+ " --param <key=value> Pass parameter to the backend.\n";
+
+ const QString exeName = QCoreApplication::instance()->arguments().first(); // e.g. debug\tst_qcommandlineparser.exe on Windows
+ expected.replace(QStringLiteral("tst_qcommandlineparser"), exeName);
+ QCOMPARE(parser.helpText(), expected);
+}
+
+void tst_QCommandLineParser::testUnknownOptionErrorHandling_data()
+{
+ QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
+ QTest::addColumn<QStringList>("args");
+ QTest::addColumn<QStringList>("expectedUnknownOptionNames");
+ QTest::addColumn<QString>("expectedErrorText");
+
+ const QStringList args_hello = QStringList() << "tst_qcommandlineparser" << "--hello";
+ const QString error_hello("Unknown option 'hello'.");
+ QTest::newRow("unknown_name_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_hello << QStringList("hello") << error_hello;
+ QTest::newRow("unknown_name_long") << QCommandLineParser::ParseAsLongOptions << args_hello << QStringList("hello") << error_hello;
+
+ const QStringList args_value = QStringList() << "tst_qcommandlineparser" << "-b=1";
+ QTest::newRow("bool_with_value_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_value << QStringList() << QString("Unexpected value after '-b'.");
+ QTest::newRow("bool_with_value_long") << QCommandLineParser::ParseAsLongOptions << args_value << QStringList() << QString("Unexpected value after '-b'.");
+
+ const QStringList args_dash_long = QStringList() << "tst_qcommandlineparser" << "-bool";
+ const QString error_bool("Unknown options: o, o, l.");
+ QTest::newRow("unknown_name_long_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_dash_long << (QStringList() << "o" << "o" << "l") << error_bool;
+}
+
+void tst_QCommandLineParser::testUnknownOptionErrorHandling()
+{
+ QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
+ QFETCH(QStringList, args);
+ QFETCH(QStringList, expectedUnknownOptionNames);
+ QFETCH(QString, expectedErrorText);
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(parsingMode);
+ QVERIFY(parser.addOption(QCommandLineOption(QStringList() << "b" << "bool", QStringLiteral("a boolean option"))));
+ QCOMPARE(parser.parse(args), expectedErrorText.isEmpty());
+ QCOMPARE(parser.unknownOptionNames(), expectedUnknownOptionNames);
+ QCOMPARE(parser.errorText(), expectedErrorText);
+}
+
+void tst_QCommandLineParser::testDoubleDash_data()
+{
+ parsingModes_data();
+}
+
+void tst_QCommandLineParser::testDoubleDash()
+{
+ QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.addOption(QCommandLineOption(QStringList() << "o" << "output", QStringLiteral("Output file"), QStringLiteral("filename")));
+ parser.setSingleDashWordOptionMode(parsingMode);
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--output" << "foo"));
+ QCOMPARE(parser.value("output"), QString("foo"));
+ QCOMPARE(parser.positionalArguments(), QStringList());
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--" << "--output" << "bar" << "-b" << "bleh"));
+ QCOMPARE(parser.value("output"), QString());
+ QCOMPARE(parser.positionalArguments(), QStringList() << "--output" << "bar" << "-b" << "bleh");
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+}
+
+void tst_QCommandLineParser::testProcessNotCalled()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"), QStringLiteral("a boolean option"))));
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before isSet");
+ QVERIFY(!parser.isSet("b"));
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before values");
+ QCOMPARE(parser.values("b"), QStringList());
+}
+
+void tst_QCommandLineParser::testEmptyArgsList()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
+ QVERIFY(!parser.parse(QStringList())); // invalid call, argv[0] is missing
+}
+
+void tst_QCommandLineParser::testMissingOptionValue()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.addOption(QCommandLineOption(QStringLiteral("option"), QStringLiteral("An option"), "value"));
+ QVERIFY(!parser.parse(QStringList() << "argv0" << "--option")); // the user forgot to pass a value for --option
+ QCOMPARE(parser.value("option"), QString());
+ QCOMPARE(parser.errorText(), QString("Missing value after '--option'."));
+}
+
+void tst_QCommandLineParser::testStdinArgument_data()
+{
+ parsingModes_data();
+}
+
+void tst_QCommandLineParser::testStdinArgument()
+{
+ QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(parsingMode);
+ parser.addOption(QCommandLineOption(QStringList() << "i" << "input", QStringLiteral("Input file."), QStringLiteral("filename")));
+ parser.addOption(QCommandLineOption("b", QStringLiteral("Boolean option.")));
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--input" << "-"));
+ QCOMPARE(parser.value("input"), QString("-"));
+ QCOMPARE(parser.positionalArguments(), QStringList());
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--input" << "-" << "-b" << "arg"));
+ QCOMPARE(parser.value("input"), QString("-"));
+ QVERIFY(parser.isSet("b"));
+ QCOMPARE(parser.positionalArguments(), QStringList() << "arg");
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+
+ QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "-"));
+ QCOMPARE(parser.value("input"), QString());
+ QVERIFY(!parser.isSet("b"));
+ QCOMPARE(parser.positionalArguments(), QStringList() << "-");
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+}
+
+void tst_QCommandLineParser::testSingleDashWordOptionModes_data()
+{
+ QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
+ QTest::addColumn<QStringList>("commandLine");
+ QTest::addColumn<QStringList>("expectedOptionNames");
+ QTest::addColumn<QStringList>("expectedOptionValues");
+
+ QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc" << "val")
+ << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
+ QTest::newRow("collapsed_with_equalsign_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc=val")
+ << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
+ QTest::newRow("collapsed_explicit_longoption") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("--nn")
+ << QStringList("nn") << QStringList();
+ QTest::newRow("collapsed_longoption_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "--abc" << "val")
+ << QStringList("abc") << QStringList("val");
+ QTest::newRow("compiler") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("-cab")
+ << QStringList("c") << QStringList("ab");
+ QTest::newRow("compiler_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
+ << QStringList("c") << QStringList("val");
+
+ QTest::newRow("implicitlylong") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc" << "val")
+ << QStringList("abc") << QStringList("val");
+ QTest::newRow("implicitlylong_equal") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc=val")
+ << QStringList("abc") << QStringList("val");
+ QTest::newRow("implicitlylong_longoption") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--nn")
+ << QStringList("nn") << QStringList();
+ QTest::newRow("implicitlylong_longoption_value") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--abc" << "val")
+ << QStringList("abc") << QStringList("val");
+ QTest::newRow("implicitlylong_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
+ << QStringList("c") << QStringList("val");
+}
+
+void tst_QCommandLineParser::testSingleDashWordOptionModes()
+{
+ QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
+ QFETCH(QStringList, commandLine);
+ QFETCH(QStringList, expectedOptionNames);
+ QFETCH(QStringList, expectedOptionValues);
+
+ commandLine.prepend("tst_QCommandLineParser");
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(parsingMode);
+ parser.addOption(QCommandLineOption("a", QStringLiteral("a option.")));
+ parser.addOption(QCommandLineOption("b", QStringLiteral("b option.")));
+ parser.addOption(QCommandLineOption(QStringList() << "c" << "abc", QStringLiteral("c option."), QStringLiteral("value")));
+ parser.addOption(QCommandLineOption("nn", QStringLiteral("nn option.")));
+ QVERIFY(parser.parse(commandLine));
+ QCOMPARE(parser.optionNames(), expectedOptionNames);
+ for (int i = 0; i < expectedOptionValues.count(); ++i)
+ QCOMPARE(parser.value(parser.optionNames().at(i)), expectedOptionValues.at(i));
+ QCOMPARE(parser.unknownOptionNames(), QStringList());
+}
+
+void tst_QCommandLineParser::testVersionOption()
+{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
+#ifdef Q_OS_WINCE
+ QSKIP("Reading and writing to a process is not supported on Qt/CE");
+#endif
+ QCoreApplication app(empty_argc, empty_argv);
+ QProcess process;
+ process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "--version");
+ QVERIFY(process.waitForFinished(5000));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QString output = process.readAll();
+#ifdef Q_OS_WIN
+ output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
+#endif
+ QCOMPARE(output, QString("qcommandlineparser_test_helper 1.0\n"));
+#endif // !QT_NO_PROCESS
+}
+
+void tst_QCommandLineParser::testHelpOption_data()
+{
+ QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
+ QTest::addColumn<QString>("expectedHelpOutput");
+
+ QString expectedOutput =
+ "Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n"
+ "Test helper\n"
+ "\n"
+ "Options:\n"
+ " -h, --help Displays this help.\n"
+ " -v, --version Displays version information.\n"
+ " --load <url> Load file from URL.\n"
+ " -o, --output <file> Set output file.\n"
+ " -D <key=value> Define macro.\n"
+ " -n, --no-implicit-includes Disable automatic generation of implicit #include\n"
+ " -directives.\n"
+ "\n"
+ "Arguments:\n"
+ " parsingMode The parsing mode to test.\n"
+ " command The command to execute.\n";
+#ifdef Q_OS_WIN
+ expectedOutput.replace(" -h, --help Displays this help.\n",
+ " -?, -h, --help Displays this help.\n");
+ expectedOutput.replace("testhelper/", "testhelper\\");
+#endif
+
+ QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << expectedOutput;
+ QTest::newRow("long") << QCommandLineParser::ParseAsLongOptions << expectedOutput;
+}
+
+void tst_QCommandLineParser::testHelpOption()
+{
+#ifdef QT_NO_PROCESS
+ QSKIP("This test requires QProcess support");
+#else
+#ifdef Q_OS_WINCE
+ QSKIP("Reading and writing to a process is not supported on Qt/CE");
+#endif
+
+ QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
+ QFETCH(QString, expectedHelpOutput);
+ QCoreApplication app(empty_argc, empty_argv);
+ QProcess process;
+ process.start("testhelper/qcommandlineparser_test_helper", QStringList() << QString::number(parsingMode) << "--help");
+ QVERIFY(process.waitForFinished(5000));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QString output = process.readAll();
+#ifdef Q_OS_WIN
+ output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
+#endif
+ QCOMPARE(output, expectedHelpOutput);
+
+ process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "resize" << "--help");
+ QVERIFY(process.waitForFinished(5000));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ output = process.readAll();
+#ifdef Q_OS_WIN
+ output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
+#endif
+ QByteArray expectedResizeHelp =
+ "Usage: testhelper/qcommandlineparser_test_helper [options] resize [resize_options]\n"
+ "Test helper\n"
+ "\n"
+ "Options:\n"
+ " -h, --help Displays this help.\n"
+ " -v, --version Displays version information.\n"
+ " --load <url> Load file from URL.\n"
+ " -o, --output <file> Set output file.\n"
+ " -D <key=value> Define macro.\n"
+ " -n, --no-implicit-includes Disable automatic generation of implicit #include\n"
+ " -directives.\n"
+ " --size <size> New size.\n"
+ "\n"
+ "Arguments:\n"
+ " resize Resize the object to a new size.\n";
+#ifdef Q_OS_WIN
+ expectedResizeHelp.replace(" -h, --help Displays this help.\n",
+ " -?, -h, --help Displays this help.\n");
+ expectedResizeHelp.replace("testhelper/", "testhelper\\");
+#endif
+ QCOMPARE(output, QString(expectedResizeHelp));
+#endif // !QT_NO_PROCESS
+}
+
+void tst_QCommandLineParser::testQuoteEscaping()
+{
+ QCoreApplication app(empty_argc, empty_argv);
+ QProcess process;
+ process.start("testhelper/qcommandlineparser_test_helper", QStringList() <<
+ QString::number(QCommandLineParser::ParseAsCompactedShortOptions) <<
+ "-DKEY1=\"VALUE1\"" << "-DKEY2=\\\"VALUE2\\\"" <<
+ "-DQTBUG-15379=C:\\path\\'file.ext" <<
+ "-DQTBUG-30628=C:\\temp\\'file'.ext");
+ QVERIFY(process.waitForFinished(5000));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QString output = process.readAll();
+ QVERIFY2(!output.contains("ERROR"), qPrintable(output));
+ QVERIFY2(output.contains("KEY1=\"VALUE1\""), qPrintable(output));
+ QVERIFY2(output.contains("KEY2=\\\"VALUE2\\\""), qPrintable(output));
+ QVERIFY2(output.contains("QTBUG-15379=C:\\path\\'file.ext"), qPrintable(output));
+ QVERIFY2(output.contains("QTBUG-30628=C:\\temp\\'file'.ext"), qPrintable(output));
+}
+
+QTEST_APPLESS_MAIN(tst_QCommandLineParser)
+#include "tst_qcommandlineparser.moc"
+
diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro
new file mode 100644
index 0000000000..6d3e6d677f
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro
@@ -0,0 +1,4 @@
+CONFIG += testcase parallel_test
+TARGET = tst_qcommandlineparser
+QT = core testlib
+SOURCES = tst_qcommandlineparser.cpp
diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/tools/qdate/tst_qdate.cpp
index 310528ba27..728a4244a1 100644
--- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/tools/qdate/tst_qdate.cpp
@@ -944,6 +944,61 @@ void tst_QDate::fromStringDateFormat_data()
QTest::newRow("iso2") << QDate(1999, 11, 14).toString(Qt::ISODate) << Qt::ISODate << QDate(1999, 11, 14);
QTest::newRow("iso3") << QString("0999-01-01") << Qt::ISODate << QDate(999, 1, 1);
QTest::newRow("iso3b") << QString("0999-01-01") << Qt::ISODate << QDate(999, 1, 1);
+
+ // Test Qt::RFC2822Date format (RFC 2822).
+ QTest::newRow("RFC 2822") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QDate(1987, 2, 13);
+ QTest::newRow("RFC 2822 with day") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QDate(1970, 1, 1);
+ // No timezone
+ QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34")
+ << Qt::RFC2822Date << QDate(1970, 1, 1);
+ // No time specified
+ QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002")
+ << Qt::RFC2822Date << QDate(2002, 11, 1);
+ QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002")
+ << Qt::RFC2822Date << QDate(2002, 11, 1);
+ // Test invalid month, day, year
+ QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100")
+ << Qt::RFC2822Date << QDate();
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!")
+ << Qt::RFC2822Date << QDate(2012, 1, 1);
+ QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << QDate();
+
+ // Test Qt::RFC2822Date format (RFC 850 and 1036).
+ QTest::newRow("RFC 850 and 1036") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100")
+ << Qt::RFC2822Date << QDate(1987, 2, 13);
+ // No timezone
+ QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970")
+ << Qt::RFC2822Date << QDate(1970, 1, 1);
+ // No time specified
+ QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002")
+ << Qt::RFC2822Date << QDate(2002, 11, 1);
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!")
+ << Qt::RFC2822Date << QDate(2012, 1, 1);
+ QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..")
+ << Qt::RFC2822Date << QDate();
+ QTest::newRow("RFC 850 and 1036 invalid character 2 at front") << QString::fromLatin1("!!Sun Jan 01 08:00:00 2012 +0000")
+ << Qt::RFC2822Date << QDate();
+
+ QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << QDate();
}
void tst_QDate::fromStringDateFormat()
@@ -1072,6 +1127,7 @@ void tst_QDate::toStringDateFormat_data()
QTest::newRow("data3") << QDate(1974,12,1) << Qt::ISODate << QString("1974-12-01");
QTest::newRow("year < 0") << QDate(-1,1,1) << Qt::ISODate << QString();
QTest::newRow("year > 9999") << QDate(-1,1,1) << Qt::ISODate << QString();
+ QTest::newRow("RFC2822Date") << QDate(1974,12,1) << Qt::RFC2822Date << QString("01 Dec 1974");
}
void tst_QDate::toStringDateFormat()
diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
index 0ec3f64020..b51fa0095c 100644
--- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
@@ -85,8 +85,11 @@ private slots:
void fromMSecsSinceEpoch();
void toString_isoDate_data();
void toString_isoDate();
+ void toString_textDate_data();
+ void toString_textDate();
+ void toString_rfcDate_data();
+ void toString_rfcDate();
void toString_enumformat();
- void toString_strformat_data();
void toString_strformat();
void addDays();
void addMonths();
@@ -127,8 +130,11 @@ private slots:
void fromStringToStringLocale_data();
void fromStringToStringLocale();
- void utcOffset();
- void setUtcOffset();
+ void offsetFromUtc();
+ void setOffsetFromUtc();
+ void toOffsetFromUtc();
+
+ void timeZoneAbbreviation();
void getDate();
@@ -137,6 +143,9 @@ private slots:
void roundtripGermanLocale() const;
void utcOffsetLessThan() const;
+ void isDaylightTime() const;
+ void daylightTransitions() const;
+
private:
bool europeanTimeZone;
QDate defDate() const { return QDate(1900, 1, 1); }
@@ -185,8 +194,11 @@ QDateTime tst_QDateTime::dt( const QString& str )
void tst_QDateTime::ctor()
{
QDateTime dt1(QDate(2004, 1, 2), QTime(1, 2, 3));
+ QCOMPARE(dt1.timeSpec(), Qt::LocalTime);
QDateTime dt2(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::LocalTime);
+ QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
QDateTime dt3(QDate(2004, 1, 2), QTime(1, 2, 3), Qt::UTC);
+ QCOMPARE(dt3.timeSpec(), Qt::UTC);
QVERIFY(dt1 == dt2);
if (europeanTimeZone) {
@@ -194,6 +206,34 @@ void tst_QDateTime::ctor()
QVERIFY(dt1 < dt3);
QVERIFY(dt1.addSecs(3600).toUTC() == dt3);
}
+
+ // Test OffsetFromUTC constructors
+ QDate offsetDate(2013, 1, 1);
+ QTime offsetTime(1, 2, 3);
+
+ QDateTime offset1(offsetDate, offsetTime, Qt::OffsetFromUTC);
+ QCOMPARE(offset1.timeSpec(), Qt::UTC);
+ QCOMPARE(offset1.offsetFromUtc(), 0);
+ QCOMPARE(offset1.date(), offsetDate);
+ QCOMPARE(offset1.time(), offsetTime);
+
+ QDateTime offset2(offsetDate, offsetTime, Qt::OffsetFromUTC, 0);
+ QCOMPARE(offset2.timeSpec(), Qt::UTC);
+ QCOMPARE(offset2.offsetFromUtc(), 0);
+ QCOMPARE(offset2.date(), offsetDate);
+ QCOMPARE(offset2.time(), offsetTime);
+
+ QDateTime offset3(offsetDate, offsetTime, Qt::OffsetFromUTC, 60 * 60);
+ QCOMPARE(offset3.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(offset3.offsetFromUtc(), 60 * 60);
+ QCOMPARE(offset3.date(), offsetDate);
+ QCOMPARE(offset3.time(), offsetTime);
+
+ QDateTime offset4(offsetDate, QTime(), Qt::OffsetFromUTC, 60 * 60);
+ QCOMPARE(offset4.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(offset4.offsetFromUtc(), 60 * 60);
+ QCOMPARE(offset4.date(), offsetDate);
+ QCOMPARE(offset4.time(), QTime(0, 0, 0));
}
void tst_QDateTime::operator_eq()
@@ -388,7 +428,10 @@ void tst_QDateTime::setTimeSpec()
QCOMPARE(dateTime.date(), expectedDate);
QCOMPARE(dateTime.time(), expectedTime);
- QCOMPARE(dateTime.timeSpec(), newTimeSpec);
+ if (newTimeSpec == Qt::OffsetFromUTC)
+ QCOMPARE(dateTime.timeSpec(), Qt::UTC);
+ else
+ QCOMPARE(dateTime.timeSpec(), newTimeSpec);
}
void tst_QDateTime::setTime_t()
@@ -396,10 +439,12 @@ void tst_QDateTime::setTime_t()
QDateTime dt1;
dt1.setTime_t(0);
QCOMPARE(dt1.toUTC(), QDateTime(QDate(1970, 1, 1), QTime(), Qt::UTC));
+ QCOMPARE(dt1.timeSpec(), Qt::LocalTime);
dt1.setTimeSpec(Qt::UTC);
dt1.setTime_t(0);
QCOMPARE(dt1, QDateTime(QDate(1970, 1, 1), QTime(), Qt::UTC));
+ QCOMPARE(dt1.timeSpec(), Qt::UTC);
dt1.setTime_t(123456);
QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC));
@@ -432,6 +477,12 @@ void tst_QDateTime::setTime_t()
dt2.setTime_t(0x7FFFFFFF);
QCOMPARE(dt2, QDateTime(QDate(2038, 1, 19), QTime(4, 14, 7), Qt::LocalTime));
}
+
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60 * 60);
+ dt1.setTime_t(123456);
+ QCOMPARE(dt1, QDateTime(QDate(1970, 1, 2), QTime(10, 17, 36), Qt::UTC));
+ QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
}
void tst_QDateTime::setMSecsSinceEpoch_data()
@@ -478,12 +529,7 @@ void tst_QDateTime::setMSecsSinceEpoch_data()
// positive value 1 too big for qint64max, causing an overflow.
<< std::numeric_limits<qint64>::min() + 1
<< QDateTime(QDate(-292275056, 5, 16), QTime(16, 47, 4, 193), Qt::UTC)
-#ifdef Q_OS_WIN
- // Windows applies Daylight Time to dates before 1980, Olsen does not
- << QDateTime(QDate(-292275056, 5, 16), QTime(18, 47, 4, 193), Qt::LocalTime);
-#else
<< QDateTime(QDate(-292275056, 5, 16), QTime(17, 47, 4, 193), Qt::LocalTime);
-#endif
QTest::newRow("max")
<< std::numeric_limits<qint64>::max()
<< QDateTime(QDate(292278994, 8, 17), QTime(7, 12, 55, 807), Qt::UTC)
@@ -501,6 +547,8 @@ void tst_QDateTime::setMSecsSinceEpoch()
dt.setMSecsSinceEpoch(msecs);
QCOMPARE(dt, utc);
+ QCOMPARE(dt.timeSpec(), Qt::UTC);
+
if (europeanTimeZone) {
QCOMPARE(dt.toLocalTime(), european);
@@ -509,7 +557,10 @@ void tst_QDateTime::setMSecsSinceEpoch()
localDt.setTimeSpec(Qt::LocalTime);
localDt.setMSecsSinceEpoch(msecs);
- QCOMPARE(localDt, utc);
+ // LocalTime will overflow for max
+ if (msecs != std::numeric_limits<qint64>::max())
+ QCOMPARE(localDt, utc);
+ QCOMPARE(localDt.timeSpec(), Qt::LocalTime);
}
QCOMPARE(dt.toMSecsSinceEpoch(), msecs);
@@ -533,26 +584,56 @@ void tst_QDateTime::fromMSecsSinceEpoch()
QFETCH(QDateTime, utc);
QFETCH(QDateTime, european);
- QDateTime dt(QDateTime::fromMSecsSinceEpoch(msecs));
+ QDateTime dtLocal = QDateTime::fromMSecsSinceEpoch(msecs, Qt::LocalTime);
+ QDateTime dtUtc = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
+ QDateTime dtOffset = QDateTime::fromMSecsSinceEpoch(msecs, Qt::OffsetFromUTC, 60*60);
- QCOMPARE(dt, utc);
- if (europeanTimeZone)
- QCOMPARE(dt.toLocalTime(), european);
+ // LocalTime will overflow for max
+ if (msecs != std::numeric_limits<qint64>::max())
+ QCOMPARE(dtLocal, utc);
- QCOMPARE(dt.toMSecsSinceEpoch(), msecs);
+ QCOMPARE(dtUtc, utc);
+ QCOMPARE(dtUtc.date(), utc.date());
+ QCOMPARE(dtUtc.time(), utc.time());
+
+ QCOMPARE(dtOffset, utc);
+ QCOMPARE(dtOffset.offsetFromUtc(), 60*60);
+ // // OffsetFromUTC will overflow for max
+ if (msecs != std::numeric_limits<qint64>::max())
+ QCOMPARE(dtOffset.time(), utc.time().addMSecs(60*60*1000));
+
+ if (europeanTimeZone) {
+ QCOMPARE(dtLocal.toLocalTime(), european);
+ QCOMPARE(dtUtc.toLocalTime(), european);
+ QCOMPARE(dtOffset.toLocalTime(), european);
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
+ }
+
+ // LocalTime will overflow for max
+ if (msecs != std::numeric_limits<qint64>::max())
+ QCOMPARE(dtLocal.toMSecsSinceEpoch(), msecs);
+ QCOMPARE(dtUtc.toMSecsSinceEpoch(), msecs);
+ QCOMPARE(dtOffset.toMSecsSinceEpoch(), msecs);
if (quint64(msecs / 1000) < 0xFFFFFFFF) {
- QCOMPARE(qint64(dt.toTime_t()), msecs / 1000);
+ QCOMPARE(qint64(dtLocal.toTime_t()), msecs / 1000);
+ QCOMPARE(qint64(dtUtc.toTime_t()), msecs / 1000);
+ QCOMPARE(qint64(dtOffset.toTime_t()), msecs / 1000);
}
QDateTime reference(QDate(1970, 1, 1), QTime(), Qt::UTC);
- QCOMPARE(dt, reference.addMSecs(msecs));
+ // LocalTime will overflow for max
+ if (msecs != std::numeric_limits<qint64>::max())
+ QCOMPARE(dtLocal, reference.addMSecs(msecs));
+ QCOMPARE(dtUtc, reference.addMSecs(msecs));
+ QCOMPARE(dtOffset, reference.addMSecs(msecs));
}
void tst_QDateTime::toString_isoDate_data()
{
- QTest::addColumn<QDateTime>("dt");
- QTest::addColumn<QString>("formatted");
+ QTest::addColumn<QDateTime>("datetime");
+ QTest::addColumn<QString>("expected");
QTest::newRow("localtime")
<< QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34))
@@ -561,7 +642,7 @@ void tst_QDateTime::toString_isoDate_data()
<< QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC)
<< QString("1978-11-09T13:28:34Z");
QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34));
- dt.setUtcOffset(19800);
+ dt.setOffsetFromUtc(19800);
QTest::newRow("positive OffsetFromUTC")
<< dt
<< QString("1978-11-09T13:28:34+05:30");
@@ -576,10 +657,106 @@ void tst_QDateTime::toString_isoDate_data()
void tst_QDateTime::toString_isoDate()
{
+ QFETCH(QDateTime, datetime);
+ QFETCH(QString, expected);
+
+ QLocale oldLocale;
+ QLocale::setDefault(QLocale("en_US"));
+
+ QString result = datetime.toString(Qt::ISODate);
+ QCOMPARE(result, expected);
+
+ QDateTime resultDatetime = QDateTime::fromString(result, Qt::ISODate);
+ // If expecting invalid result the datetime may still be valid, i.e. year < 0 or > 9999
+ if (!expected.isEmpty()) {
+ QCOMPARE(resultDatetime, datetime);
+ QCOMPARE(resultDatetime.date(), datetime.date());
+ QCOMPARE(resultDatetime.time(), datetime.time());
+ QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec());
+ QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset());
+ } else {
+ QCOMPARE(resultDatetime, QDateTime());
+ }
+
+ QLocale::setDefault(oldLocale);
+}
+
+void tst_QDateTime::toString_textDate_data()
+{
+ QTest::addColumn<QDateTime>("datetime");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::LocalTime)
+ << QString("Wed Jan 2 01:02:03 2013");
+ QTest::newRow("utc") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::UTC)
+ << QString("Wed Jan 2 01:02:03 2013 GMT");
+ QTest::newRow("offset+") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::OffsetFromUTC,
+ 10 * 60 * 60)
+ << QString("Wed Jan 2 01:02:03 2013 GMT+1000");
+ QTest::newRow("offset-") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::OffsetFromUTC,
+ -10 * 60 * 60)
+ << QString("Wed Jan 2 01:02:03 2013 GMT-1000");
+ QTest::newRow("invalid") << QDateTime()
+ << QString("");
+}
+
+void tst_QDateTime::toString_textDate()
+{
+ QFETCH(QDateTime, datetime);
+ QFETCH(QString, expected);
+
+ QLocale oldLocale;
+ QLocale::setDefault(QLocale("en_US"));
+
+ QString result = datetime.toString(Qt::TextDate);
+ QCOMPARE(result, expected);
+
+ QDateTime resultDatetime = QDateTime::fromString(result, Qt::TextDate);
+ QCOMPARE(resultDatetime, datetime);
+ QCOMPARE(resultDatetime.date(), datetime.date());
+ QCOMPARE(resultDatetime.time(), datetime.time());
+ QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec());
+ QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset());
+
+ QLocale::setDefault(oldLocale);
+}
+
+void tst_QDateTime::toString_rfcDate_data()
+{
+ QTest::addColumn<QDateTime>("dt");
+ QTest::addColumn<QString>("formatted");
+
+ if (europeanTimeZone) {
+ QTest::newRow("localtime")
+ << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34))
+ << QString("09 Nov 1978 13:28:34 +0100");
+ }
+ QTest::newRow("UTC")
+ << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC)
+ << QString("09 Nov 1978 13:28:34 +0000");
+ QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34));
+ dt.setUtcOffset(19800);
+ QTest::newRow("positive OffsetFromUTC")
+ << dt
+ << QString("09 Nov 1978 13:28:34 +0530");
+ dt.setUtcOffset(-7200);
+ QTest::newRow("negative OffsetFromUTC")
+ << dt
+ << QString("09 Nov 1978 13:28:34 -0200");
+ QTest::newRow("invalid")
+ << QDateTime(QDate(1978, 13, 9), QTime(13, 28, 34), Qt::UTC)
+ << QString();
+ QTest::newRow("999 milliseconds UTC")
+ << QDateTime(QDate(2000, 1, 1), QTime(13, 28, 34, 999), Qt::UTC)
+ << QString("01 Jan 2000 13:28:34 +0000");
+}
+
+void tst_QDateTime::toString_rfcDate()
+{
QFETCH(QDateTime, dt);
QFETCH(QString, formatted);
- QCOMPARE(dt.toString(Qt::ISODate), formatted);
+ QCOMPARE(dt.toString(Qt::RFC2822Date), formatted);
}
void tst_QDateTime::toString_enumformat()
@@ -630,6 +807,26 @@ void tst_QDateTime::addDays()
QCOMPARE(dt.time(), QTime(12, 34, 56));
}
+ // Test preserves TimeSpec
+ QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QDateTime dt2 = dt1.addDays(2);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 3));
+ QCOMPARE(dt2.time(), QTime(0, 0, 0));
+ QCOMPARE(dt2.timeSpec(), Qt::UTC);
+
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
+ dt2 = dt1.addDays(2);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 3));
+ QCOMPARE(dt2.time(), QTime(0, 0, 0));
+ QCOMPARE(dt2.timeSpec(), Qt::LocalTime);
+
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60*60);
+ dt2 = dt1.addDays(2);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 3));
+ QCOMPARE(dt2.time(), QTime(0, 0, 0));
+ QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt2.offsetFromUtc(), 60 * 60);
+
// ### test invalid QDateTime()
}
@@ -637,7 +834,7 @@ void tst_QDateTime::addDays()
void tst_QDateTime::addMonths_data()
{
QTest::addColumn<int>("months");
- QTest::addColumn<QDate>("dt");
+ QTest::addColumn<QDate>("resultDate");
QTest::newRow("-15") << -15 << QDate(2002, 10, 31);
QTest::newRow("-14") << -14 << QDate(2002, 11, 30);
@@ -675,20 +872,37 @@ void tst_QDateTime::addMonths_data()
void tst_QDateTime::addMonths()
{
- QFETCH(QDate, dt);
QFETCH(int, months);
-
- QDateTime start(QDate(2004, 1, 31), QTime(12, 34, 56));
- QCOMPARE(start.addMonths(months).date(), dt);
- QCOMPARE(start.addMonths(months).time(), QTime(12, 34, 56));
+ QFETCH(QDate, resultDate);
+
+ QDate testDate(2004, 1, 31);
+ QTime testTime(12, 34, 56);
+ QDateTime start(testDate, testTime);
+ QDateTime end = start.addMonths(months);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::LocalTime);
+
+ start = QDateTime(testDate, testTime, Qt::UTC);
+ end = start.addMonths(months);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::UTC);
+
+ start = QDateTime(testDate, testTime, Qt::OffsetFromUTC, 60 * 60);
+ end = start.addMonths(months);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(end.offsetFromUtc(), 60 * 60);
}
void tst_QDateTime::addYears_data()
{
QTest::addColumn<int>("years1");
QTest::addColumn<int>("years2");
- QTest::addColumn<QDate>("start");
- QTest::addColumn<QDate>("dt");
+ QTest::addColumn<QDate>("startDate");
+ QTest::addColumn<QDate>("resultDate");
QTest::newRow("0") << 0 << 0 << QDate(1752, 9, 14) << QDate(1752, 9, 14);
QTest::newRow("4000 - 4000") << 4000 << -4000 << QDate(1752, 9, 14) << QDate(1752, 9, 14);
@@ -711,12 +925,28 @@ void tst_QDateTime::addYears()
{
QFETCH(int, years1);
QFETCH(int, years2);
- QFETCH(QDate, start);
- QFETCH(QDate, dt);
-
- QDateTime startdt(start, QTime(14, 25, 36));
- QCOMPARE(startdt.addYears(years1).addYears(years2).date(), dt);
- QCOMPARE(startdt.addYears(years1).addYears(years2).time(), QTime(14, 25, 36));
+ QFETCH(QDate, startDate);
+ QFETCH(QDate, resultDate);
+
+ QTime testTime(14, 25, 36);
+ QDateTime start(startDate, testTime);
+ QDateTime end = start.addYears(years1).addYears(years2);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::LocalTime);
+
+ start = QDateTime(startDate, testTime, Qt::UTC);
+ end = start.addYears(years1).addYears(years2);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::UTC);
+
+ start = QDateTime(startDate, testTime, Qt::OffsetFromUTC, 60 * 60);
+ end = start.addYears(years1).addYears(years2);
+ QCOMPARE(end.date(), resultDate);
+ QCOMPARE(end.time(), testTime);
+ QCOMPARE(end.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(end.offsetFromUtc(), 60 * 60);
}
void tst_QDateTime::addSecs_data()
@@ -758,15 +988,8 @@ void tst_QDateTime::addSecs_data()
<< QDateTime(QDate(2005, 1, 1), standardTime, Qt::LocalTime);
QTest::newRow("cet3") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << 86400
<< QDateTime(QDate(1760, 1, 2), standardTime, Qt::LocalTime);
-#ifdef Q_OS_WIN
- // QDateTime uses 1980 on Windows, which did have daylight savings in July
- QTest::newRow("cet4") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 185)
- << QDateTime(QDate(1760, 7, 4), daylightTime, Qt::LocalTime);
-#else
- // QDateTime uses 1970 everywhere else, which did NOT have daylight savings in July
QTest::newRow("cet4") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 185)
<< QDateTime(QDate(1760, 7, 4), standardTime, Qt::LocalTime);
-#endif
QTest::newRow("cet5") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 366)
<< QDateTime(QDate(1761, 1, 1), standardTime, Qt::LocalTime);
QTest::newRow("cet6") << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << 86400
@@ -788,6 +1011,13 @@ void tst_QDateTime::addSecs_data()
<< QDateTime(QDate(1, 1, 1), QTime(0, 0, 0), Qt::UTC);
QTest::newRow("invalid") << invalidDateTime() << 1 << invalidDateTime();
+
+ // Check Offset details are preserved
+ QTest::newRow("offset0") << QDateTime(QDate(2013, 1, 1), QTime(1, 2, 3),
+ Qt::OffsetFromUTC, 60 * 60)
+ << 60 * 60
+ << QDateTime(QDate(2013, 1, 1), QTime(2, 2, 3),
+ Qt::OffsetFromUTC, 60 * 60);
}
void tst_QDateTime::addSecs()
@@ -795,11 +1025,14 @@ void tst_QDateTime::addSecs()
QFETCH(QDateTime, dt);
QFETCH(int, nsecs);
QFETCH(QDateTime, result);
-
#ifdef Q_OS_IRIX
QEXPECT_FAIL("cet4", "IRIX databases say 1970 had DST", Abort);
#endif
- QCOMPARE(dt.addSecs(nsecs), result);
+ QDateTime test = dt.addSecs(nsecs);
+ QCOMPARE(test, result);
+ QCOMPARE(test.timeSpec(), dt.timeSpec());
+ if (test.timeSpec() == Qt::OffsetFromUTC)
+ QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
QCOMPARE(result.addSecs(-nsecs), dt);
}
@@ -817,14 +1050,18 @@ void tst_QDateTime::addMSecs()
#ifdef Q_OS_IRIX
QEXPECT_FAIL("cet4", "IRIX databases say 1970 had DST", Abort);
#endif
- QCOMPARE(dt.addMSecs(qint64(nsecs) * 1000), result);
+ QDateTime test = dt.addMSecs(qint64(nsecs) * 1000);
+ QCOMPARE(test, result);
+ QCOMPARE(test.timeSpec(), dt.timeSpec());
+ if (test.timeSpec() == Qt::OffsetFromUTC)
+ QCOMPARE(test.offsetFromUtc(), dt.offsetFromUtc());
QCOMPARE(result.addMSecs(qint64(-nsecs) * 1000), dt);
}
void tst_QDateTime::toTimeSpec_data()
{
- QTest::addColumn<QDateTime>("utc");
- QTest::addColumn<QDateTime>("local");
+ QTest::addColumn<QDateTime>("fromUtc");
+ QTest::addColumn<QDateTime>("fromLocal");
QTime utcTime(4, 20, 30);
QTime localStandardTime(5, 20, 30);
@@ -849,41 +1086,16 @@ void tst_QDateTime::toTimeSpec_data()
QTest::newRow("-271821/4/20 00:00 UTC (JavaScript min date, start of day)")
<< QDateTime(QDate(-271821, 4, 20), QTime(0, 0, 0), Qt::UTC)
-#ifdef Q_OS_WIN
- // Windows applies Daylight Time to dates before 1980, Olsen does not
- << QDateTime(QDate(-271821, 4, 20), QTime(2, 0, 0), Qt::LocalTime);
-#else
<< QDateTime(QDate(-271821, 4, 20), QTime(1, 0, 0), Qt::LocalTime);
-#endif
QTest::newRow("-271821/4/20 23:00 UTC (JavaScript min date, end of day)")
<< QDateTime(QDate(-271821, 4, 20), QTime(23, 0, 0), Qt::UTC)
-#ifdef Q_OS_WIN
- // Windows applies Daylight Time to dates before 1980, Olsen does not
- << QDateTime(QDate(-271821, 4, 21), QTime(1, 0, 0), Qt::LocalTime);
-#else
<< QDateTime(QDate(-271821, 4, 21), QTime(0, 0, 0), Qt::LocalTime);
-#endif
-
- QTest::newRow("QDate min")
- << QDateTime(QDate::fromJulianDay(minJd()), QTime(0, 0, 0), Qt::UTC)
- << QDateTime(QDate::fromJulianDay(minJd()), QTime(1, 0, 0), Qt::LocalTime);
-
- QTest::newRow("QDate max")
- << QDateTime(QDate::fromJulianDay(maxJd()), QTime(22, 59, 59), Qt::UTC)
- << QDateTime(QDate::fromJulianDay(maxJd()), QTime(23, 59, 59), Qt::LocalTime);
if (europeanTimeZone) {
QTest::newRow("summer1") << QDateTime(QDate(2004, 6, 30), utcTime, Qt::UTC)
<< QDateTime(QDate(2004, 6, 30), localDaylightTime, Qt::LocalTime);
-#ifdef Q_OS_WIN
- // QDateTime uses 1980 on Windows, which did have daylight savings in July
- QTest::newRow("summer2") << QDateTime(QDate(1760, 6, 30), utcTime, Qt::UTC)
- << QDateTime(QDate(1760, 6, 30), localDaylightTime, Qt::LocalTime);
-#else
- // QDateTime uses 1970 everywhere else, which did NOT have daylight savings in July
QTest::newRow("summer2") << QDateTime(QDate(1760, 6, 30), utcTime, Qt::UTC)
<< QDateTime(QDate(1760, 6, 30), localStandardTime, Qt::LocalTime);
-#endif
QTest::newRow("summer3") << QDateTime(QDate(4000, 6, 30), utcTime, Qt::UTC)
<< QDateTime(QDate(4000, 6, 30), localDaylightTime, Qt::LocalTime);
@@ -903,18 +1115,59 @@ void tst_QDateTime::toTimeSpec_data()
void tst_QDateTime::toTimeSpec()
{
if (europeanTimeZone) {
- QFETCH(QDateTime, utc);
- QFETCH(QDateTime, local);
+ QFETCH(QDateTime, fromUtc);
+ QFETCH(QDateTime, fromLocal);
+
+ QDateTime utcToUtc = fromUtc.toTimeSpec(Qt::UTC);
+ QDateTime localToLocal = fromLocal.toTimeSpec(Qt::LocalTime);
+ QDateTime utcToLocal = fromUtc.toTimeSpec(Qt::LocalTime);
+ QDateTime localToUtc = fromLocal.toTimeSpec(Qt::UTC);
+ QDateTime utcToOffset = fromUtc.toTimeSpec(Qt::OffsetFromUTC);
+ QDateTime localToOffset = fromLocal.toTimeSpec(Qt::OffsetFromUTC);
+
+ QCOMPARE(utcToUtc, fromUtc);
+ QCOMPARE(utcToUtc.date(), fromUtc.date());
+ QCOMPARE(utcToUtc.time(), fromUtc.time());
+ QCOMPARE(utcToUtc.timeSpec(), Qt::UTC);
+
+ QCOMPARE(localToLocal, fromLocal);
+ QCOMPARE(localToLocal.date(), fromLocal.date());
+ QCOMPARE(localToLocal.time(), fromLocal.time());
+ QCOMPARE(localToLocal.timeSpec(), Qt::LocalTime);
- QCOMPARE(utc.toTimeSpec(Qt::UTC), utc);
- QCOMPARE(local.toTimeSpec(Qt::LocalTime), local);
#ifdef Q_OS_IRIX
QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort);
#endif
- QCOMPARE(utc.toTimeSpec(Qt::LocalTime), local);
- QCOMPARE(local.toTimeSpec(Qt::UTC), utc);
- QCOMPARE(utc.toTimeSpec(Qt::UTC), local.toTimeSpec(Qt::UTC));
- QCOMPARE(utc.toTimeSpec(Qt::LocalTime), local.toTimeSpec(Qt::LocalTime));
+ QCOMPARE(utcToLocal, fromLocal);
+ QCOMPARE(utcToLocal.date(), fromLocal.date());
+ QCOMPARE(utcToLocal.time(), fromLocal.time());
+ QCOMPARE(utcToLocal.timeSpec(), Qt::LocalTime);
+
+ QCOMPARE(localToUtc, fromUtc);
+ QCOMPARE(localToUtc.date(), fromUtc.date());
+ QCOMPARE(localToUtc.time(), fromUtc.time());
+ QCOMPARE(localToUtc.timeSpec(), Qt::UTC);
+
+ QCOMPARE(utcToUtc, localToUtc);
+ QCOMPARE(utcToUtc.date(), localToUtc.date());
+ QCOMPARE(utcToUtc.time(), localToUtc.time());
+ QCOMPARE(utcToUtc.timeSpec(), Qt::UTC);
+
+ QCOMPARE(utcToLocal, localToLocal);
+ QCOMPARE(utcToLocal.date(), localToLocal.date());
+ QCOMPARE(utcToLocal.time(), localToLocal.time());
+ QCOMPARE(utcToLocal.timeSpec(), Qt::LocalTime);
+
+ // OffsetToUTC becomes UTC
+ QCOMPARE(utcToOffset, fromUtc);
+ QCOMPARE(utcToOffset.date(), fromUtc.date());
+ QCOMPARE(utcToOffset.time(), fromUtc.time());
+ QCOMPARE(utcToOffset.timeSpec(), Qt::UTC);
+
+ QCOMPARE(localToOffset, fromUtc);
+ QCOMPARE(localToOffset.date(), fromUtc.date());
+ QCOMPARE(localToOffset.time(), fromUtc.time());
+ QCOMPARE(localToOffset.timeSpec(), Qt::UTC);
} else {
QSKIP("Not tested with timezone other than Central European (CET/CST)");
}
@@ -928,15 +1181,15 @@ void tst_QDateTime::toLocalTime_data()
void tst_QDateTime::toLocalTime()
{
if (europeanTimeZone) {
- QFETCH(QDateTime, utc);
- QFETCH(QDateTime, local);
+ QFETCH(QDateTime, fromUtc);
+ QFETCH(QDateTime, fromLocal);
- QCOMPARE(local.toLocalTime(), local);
+ QCOMPARE(fromLocal.toLocalTime(), fromLocal);
#ifdef Q_OS_IRIX
QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort);
#endif
- QCOMPARE(utc.toLocalTime(), local);
- QCOMPARE(utc.toLocalTime(), local.toLocalTime());
+ QCOMPARE(fromUtc.toLocalTime(), fromLocal);
+ QCOMPARE(fromUtc.toLocalTime(), fromLocal.toLocalTime());
} else {
QSKIP("Not tested with timezone other than Central European (CET/CST)");
}
@@ -950,15 +1203,15 @@ void tst_QDateTime::toUTC_data()
void tst_QDateTime::toUTC()
{
if (europeanTimeZone) {
- QFETCH(QDateTime, utc);
- QFETCH(QDateTime, local);
+ QFETCH(QDateTime, fromUtc);
+ QFETCH(QDateTime, fromLocal);
- QCOMPARE(utc.toUTC(), utc);
+ QCOMPARE(fromUtc.toUTC(), fromUtc);
#ifdef Q_OS_IRIX
QEXPECT_FAIL("summer2", "IRIX databases say 1970 had DST", Abort);
#endif
- QCOMPARE(local.toUTC(), utc);
- QCOMPARE(utc.toUTC(), local.toUTC());
+ QCOMPARE(fromLocal.toUTC(), fromUtc);
+ QCOMPARE(fromUtc.toUTC(), fromLocal.toUTC());
} else {
QSKIP("Not tested with timezone other than Central European (CET/CST)");
}
@@ -1288,9 +1541,9 @@ void tst_QDateTime::operator_eqeq_data()
QDateTime dateTime3b = dateTime3.addDays(-1);
// Ensure that different times may be equal when considering timezone.
QDateTime dateTime3c(dateTime3.addSecs(3600));
- dateTime3c.setUtcOffset(3600);
+ dateTime3c.setOffsetFromUtc(3600);
QDateTime dateTime3d(dateTime3.addSecs(-3600));
- dateTime3d.setUtcOffset(-3600);
+ dateTime3d.setOffsetFromUtc(-3600);
// Convert from UTC to local.
QDateTime dateTime3e(dateTime3.date(), dateTime3.time());
@@ -1387,8 +1640,9 @@ void tst_QDateTime::operator_insert_extract()
QFETCH(QString, deserialiseAs);
QFETCH(QDataStream::Version, dataStreamVersion);
- // Save the previous timezone so we can restore it afterwards, just in case.
- QString previousTimeZone = qgetenv("TZ");
+ // Save the previous timezone so we can restore it afterwards, otherwise later tests will break
+ QByteArray previousTimeZone = qgetenv("TZ");
+
// Start off in a certain timezone.
qputenv("TZ", serialiseAs.toLocal8Bit().constData());
tzset();
@@ -1469,69 +1723,23 @@ void tst_QDateTime::operator_insert_extract()
}
}
- qputenv("TZ", previousTimeZone.toLocal8Bit().constData());
+ if (previousTimeZone.isNull())
+ qunsetenv("TZ");
+ else
+ qputenv("TZ", previousTimeZone.constData());
tzset();
}
#endif
-void tst_QDateTime::toString_strformat_data()
-{
- QTest::addColumn<QDateTime>("dt");
- QTest::addColumn<QString>("format");
- QTest::addColumn<QString>("str");
-
- QTest::newRow( "datetime0" ) << QDateTime() << QString("dd-MM-yyyy hh:mm:ss") << QString();
- QTest::newRow( "datetime1" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("dd-'mmddyy'MM-yyyy hh:mm:ss.zzz")
- << QString("31-mmddyy12-1999 23:59:59.999");
- QTest::newRow( "datetime2" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("dd-'apAP'MM-yyyy hh:mm:ss.zzz")
- << QString("31-apAP12-1999 23:59:59.999");
- QTest::newRow( "datetime3" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("Apdd-MM-yyyy hh:mm:ss.zzz")
- << QString("PMp31-12-1999 11:59:59.999");
- QTest::newRow( "datetime4" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("'ap'apdd-MM-yyyy 'AP'hh:mm:ss.zzz")
- << QString("appm31-12-1999 AP11:59:59.999");
- QTest::newRow( "datetime5" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("'''") << QString("'");
- QTest::newRow( "datetime6" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("'ap") << QString("ap");
- QTest::newRow( "datetime7" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("' ' 'hh' hh") << QString(" hh 23");
- QTest::newRow( "datetime8" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("d'foobar'") << QString("31foobar");
- QTest::newRow( "datetime9" ) << QDateTime(QDate(1999, 12, 31), QTime(3, 59, 59, 999))
- << QString("hhhhh") << QString("03033");
- QTest::newRow( "datetime11" ) << QDateTime(QDate(1999, 12, 31), QTime(23, 59, 59, 999))
- << QString("HHHhhhAaAPap") << QString("23231111PMpmPMpm");
- QTest::newRow( "datetime12" ) << QDateTime(QDate(1999, 12, 31), QTime(3, 59, 59, 999))
- << QString("HHHhhhAaAPap") << QString("033033AMamAMam");
- QTest::newRow( "datetime13" ) << QDateTime(QDate(1974, 12, 1), QTime(14, 14, 20))
- << QString("hh''mm''ss dd''MM''yyyy")
- << QString("14'14'20 01'12'1974");
- QTest::newRow( "single, 0 => 12 AM" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("hAP") << QString("12AM");
- QTest::newRow( "double, 0 => 12 AM" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("hhAP") << QString("12AM");
- QTest::newRow( "dddd" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("dddd") << QString("Friday");
- QTest::newRow( "ddd" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("ddd") << QString("Fri");
- QTest::newRow( "MMMM" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("MMMM") << QString("December");
- QTest::newRow( "MMM" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("MMM") << QString("Dec");
- QTest::newRow( "emtpy" ) << QDateTime(QDate(1999, 12, 31), QTime(0, 59, 59, 999))
- << QString("") << QString("");
-}
-
void tst_QDateTime::toString_strformat()
{
- QFETCH( QDateTime, dt );
- QFETCH( QString, format );
- QFETCH( QString, str );
- QCOMPARE( dt.toString( format ), str );
+ // Most tests are in QLocale, just test that the api works.
+ QDate testDate(2013, 1, 1);
+ QTime testTime(1, 2, 3);
+ QDateTime testDateTime(testDate, testTime, Qt::UTC);
+ QCOMPARE(testDate.toString("yyyy-MM-dd"), QString("2013-01-01"));
+ QCOMPARE(testTime.toString("hh:mm:ss"), QString("01:02:03"));
+ QCOMPARE(testDateTime.toString("yyyy-MM-dd hh:mm:ss t"), QString("2013-01-01 01:02:03 UTC"));
}
void tst_QDateTime::fromStringDateFormat_data()
@@ -1586,7 +1794,7 @@ void tst_QDateTime::fromStringDateFormat_data()
QTest::newRow("text invalid month name") << QString::fromLatin1("Thu Jaz 1 1970 00:12:34")
<< Qt::TextDate << invalidDateTime();
QTest::newRow("text invalid date") << QString::fromLatin1("Thu Jan 32 1970 00:12:34")
- << Qt::TextDate << QDateTime(invalidDate(), QTime(0, 12, 34), Qt::LocalTime);
+ << Qt::TextDate << invalidDateTime();
QTest::newRow("text invalid day #1") << QString::fromLatin1("Thu Jan XX 1970 00:12:34")
<< Qt::TextDate << invalidDateTime();
QTest::newRow("text invalid day #2") << QString::fromLatin1("Thu X. Jan 00:00:00 1970")
@@ -1611,18 +1819,18 @@ void tst_QDateTime::fromStringDateFormat_data()
<< Qt::TextDate << invalidDateTime();
QTest::newRow("text invalid gmt minute") << QString::fromLatin1("Thu 1. Jan 1970 00:00:00 GMT+000X")
<< Qt::TextDate << invalidDateTime();
+ QTest::newRow("text second fraction") << QString::fromLatin1("Mon 6. May 2013 01:02:03.456")
+ << Qt::TextDate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456));
// Test Qt::ISODate format.
QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00")
<< Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
QTest::newRow("ISO -01:00") << QString::fromLatin1("1987-02-13T13:24:51-01:00")
<< Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
- // Not sure about these two... it will currently be created as LocalTime, but it
- // should probably be UTC according to the ISO 8601 spec (see 4.2.5.1).
QTest::newRow("ISO +0000") << QString::fromLatin1("1970-01-01T00:12:34+0000")
- << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
QTest::newRow("ISO +00:00") << QString::fromLatin1("1970-01-01T00:12:34+00:00")
- << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::LocalTime);
+ << Qt::ISODate << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
// No time specified - defaults to Qt::LocalTime.
QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01")
<< Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0), Qt::LocalTime);
@@ -1697,6 +1905,79 @@ void tst_QDateTime::fromStringDateFormat_data()
QTest::newRow("ISO .99999 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,99999")
<< Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime);
QTest::newRow("ISO empty") << QString::fromLatin1("") << Qt::ISODate << invalidDateTime();
+
+ // Test Qt::RFC2822Date format (RFC 2822).
+ QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 2822 with day +0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 2822 -0100") << QString::fromLatin1("13 Feb 1987 13:24:51 -0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 2822 with day -0100") << QString::fromLatin1("Fri, 13 Feb 1987 13:24:51 -0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ QTest::newRow("RFC 2822 +0000") << QString::fromLatin1("01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ QTest::newRow("RFC 2822 with day +0000") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ // No timezone assume UTC
+ QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ // No time specified
+ QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002")
+ << Qt::RFC2822Date << invalidDateTime();
+ // Test invalid month, day, year
+ QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100")
+ << Qt::RFC2822Date << invalidDateTime();
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!")
+ << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0, 0, 0), Qt::UTC);
+ QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << invalidDateTime();
+
+ // Test Qt::RFC2822Date format (RFC 850 and 1036).
+ QTest::newRow("RFC 850 and 1036 +0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 850 and 1036 -0100") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 -0100")
+ << Qt::RFC2822Date << QDateTime(QDate(1987, 2, 13), QTime(14, 24, 51), Qt::UTC);
+ QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ QTest::newRow("RFC 850 and 1036 +0000") << QString::fromLatin1("Thu Jan 01 00:12:34 1970 +0000")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ // No timezone assume UTC
+ QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970")
+ << Qt::RFC2822Date << QDateTime(QDate(1970, 1, 1), QTime(0, 12, 34), Qt::UTC);
+ // No time specified
+ QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002")
+ << Qt::RFC2822Date << invalidDateTime();
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!")
+ << Qt::RFC2822Date << QDateTime(QDate(2012, 1, 1), QTime(7, 0, 0, 0), Qt::UTC);
+ QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..")
+ << Qt::RFC2822Date << invalidDateTime();
+ QTest::newRow("RFC 850 and 1036 invalid character 2 at front") << QString::fromLatin1("!!Sun Jan 01 08:00:00 2012 +0000")
+ << Qt::RFC2822Date << invalidDateTime();
+
+ QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << invalidDateTime();
}
void tst_QDateTime::fromStringDateFormat()
@@ -1800,25 +2081,47 @@ void tst_QDateTime::fromStringToStringLocale()
QLocale::setDefault(def);
}
-void tst_QDateTime::utcOffset()
+void tst_QDateTime::offsetFromUtc()
{
/* Check default value. */
- QCOMPARE(QDateTime().utcOffset(), 0);
+ QCOMPARE(QDateTime().offsetFromUtc(), 0);
+
+ // Offset constructor
+ QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60);
+ QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
+ dt1 = QDateTime(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60);
+ QCOMPARE(dt1.offsetFromUtc(), -60 * 60);
+
+ // UTC should be 0 offset
+ QDateTime dt2(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QCOMPARE(dt2.offsetFromUtc(), 0);
+
+ // LocalTime should vary
+ if (europeanTimeZone) {
+ // Time definitely in Standard Time so 1 hour ahead
+ QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
+ QCOMPARE(dt3.offsetFromUtc(), 1 * 60 * 60);
+ // Time definitely in Daylight Time so 2 hours ahead
+ QDateTime dt4(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime);
+ QCOMPARE(dt4.offsetFromUtc(), 2 * 60 * 60);
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
+ }
}
-void tst_QDateTime::setUtcOffset()
+void tst_QDateTime::setOffsetFromUtc()
{
/* Basic tests. */
{
QDateTime dt(QDateTime::currentDateTime());
dt.setTimeSpec(Qt::LocalTime);
- dt.setUtcOffset(0);
- QCOMPARE(dt.utcOffset(), 0);
+ dt.setOffsetFromUtc(0);
+ QCOMPARE(dt.offsetFromUtc(), 0);
QCOMPARE(dt.timeSpec(), Qt::UTC);
- dt.setUtcOffset(-100);
- QCOMPARE(dt.utcOffset(), -100);
+ dt.setOffsetFromUtc(-100);
+ QCOMPARE(dt.offsetFromUtc(), -100);
QCOMPARE(dt.timeSpec(), Qt::OffsetFromUTC);
}
@@ -1826,31 +2129,108 @@ void tst_QDateTime::setUtcOffset()
{
QDateTime dt(QDateTime::currentDateTime());
QDateTime dt2(dt);
+ int offset2 = dt2.offsetFromUtc();
- dt.setUtcOffset(501);
+ dt.setOffsetFromUtc(501);
- QCOMPARE(dt.utcOffset(), 501);
- QCOMPARE(dt2.utcOffset(), 0);
+ QCOMPARE(dt.offsetFromUtc(), 501);
+ QCOMPARE(dt2.offsetFromUtc(), offset2);
}
/* Check copying. */
{
QDateTime dt(QDateTime::currentDateTime());
- dt.setUtcOffset(502);
- QCOMPARE(dt.utcOffset(), 502);
+ dt.setOffsetFromUtc(502);
+ QCOMPARE(dt.offsetFromUtc(), 502);
QDateTime dt2(dt);
- QCOMPARE(dt2.utcOffset(), 502);
+ QCOMPARE(dt2.offsetFromUtc(), 502);
}
/* Check assignment. */
{
QDateTime dt(QDateTime::currentDateTime());
- dt.setUtcOffset(502);
+ dt.setOffsetFromUtc(502);
QDateTime dt2;
dt2 = dt;
- QCOMPARE(dt2.utcOffset(), 502);
+ QCOMPARE(dt2.offsetFromUtc(), 502);
+ }
+
+ // Check spec persists
+ QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 60 * 60);
+ dt1.setMSecsSinceEpoch(123456789);
+ QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
+ dt1.setTime_t(123456789);
+ QCOMPARE(dt1.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt1.offsetFromUtc(), 60 * 60);
+
+ // Check datastream serialises the offset seconds
+ QByteArray tmp;
+ {
+ QDataStream ds(&tmp, QIODevice::WriteOnly);
+ ds << dt1;
+ }
+ QDateTime dt2;
+ {
+ QDataStream ds(&tmp, QIODevice::ReadOnly);
+ ds >> dt2;
+ }
+ QCOMPARE(dt2, dt1);
+ QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt2.offsetFromUtc(), 60 * 60);
+}
+
+void tst_QDateTime::toOffsetFromUtc()
+{
+ QDateTime dt1(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
+
+ QDateTime dt2 = dt1.toOffsetFromUtc(60 * 60);
+ QCOMPARE(dt2, dt1);
+ QCOMPARE(dt2.timeSpec(), Qt::OffsetFromUTC);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 1));
+ QCOMPARE(dt2.time(), QTime(1, 0, 0));
+
+ dt2 = dt1.toOffsetFromUtc(0);
+ QCOMPARE(dt2, dt1);
+ QCOMPARE(dt2.timeSpec(), Qt::UTC);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 1));
+ QCOMPARE(dt2.time(), QTime(0, 0, 0));
+
+ dt2 = dt1.toTimeSpec(Qt::OffsetFromUTC);
+ QCOMPARE(dt2, dt1);
+ QCOMPARE(dt2.timeSpec(), Qt::UTC);
+ QCOMPARE(dt2.date(), QDate(2013, 1, 1));
+ QCOMPARE(dt2.time(), QTime(0, 0, 0));
+}
+
+void tst_QDateTime::timeZoneAbbreviation()
+{
+ QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60);
+ QCOMPARE(dt1.timeZoneAbbreviation(), QString("UTC+01:00"));
+ QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60);
+ QCOMPARE(dt2.timeZoneAbbreviation(), QString("UTC-01:00"));
+
+ QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QCOMPARE(dt3.timeZoneAbbreviation(), QString("UTC"));
+
+ // LocalTime should vary
+ if (europeanTimeZone) {
+ // Time definitely in Standard Time
+ QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
+#ifdef Q_OS_WIN
+ QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET"));
+ // Time definitely in Daylight Time
+ QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime);
+#ifdef Q_OS_WIN
+ QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST"));
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
}
}
@@ -1928,8 +2308,8 @@ void tst_QDateTime::utcOffsetLessThan() const
QDateTime dt1(QDate(2002, 10, 10), QTime(0, 0, 0));
QDateTime dt2(dt1);
- dt1.setUtcOffset(-(2 * 60 * 60)); // Minus two hours.
- dt2.setUtcOffset(-(3 * 60 * 60)); // Minus three hours.
+ dt1.setOffsetFromUtc(-(2 * 60 * 60)); // Minus two hours.
+ dt2.setOffsetFromUtc(-(3 * 60 * 60)); // Minus three hours.
QVERIFY(dt1 != dt2);
QVERIFY(!(dt1 == dt2));
@@ -1937,5 +2317,405 @@ void tst_QDateTime::utcOffsetLessThan() const
QVERIFY(!(dt2 < dt1));
}
+void tst_QDateTime::isDaylightTime() const
+{
+ QDateTime utc1(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QVERIFY(!utc1.isDaylightTime());
+ QDateTime utc2(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC);
+ QVERIFY(!utc2.isDaylightTime());
+
+ QDateTime offset1(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 1 * 60 * 60);
+ QVERIFY(!offset1.isDaylightTime());
+ QDateTime offset2(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::OffsetFromUTC, 1 * 60 * 60);
+ QVERIFY(!offset2.isDaylightTime());
+
+ if (europeanTimeZone) {
+ QDateTime cet1(QDate(2012, 1, 1), QTime(0, 0, 0));
+ QVERIFY(!cet1.isDaylightTime());
+ QDateTime cet2(QDate(2012, 6, 1), QTime(0, 0, 0));
+ QVERIFY(cet2.isDaylightTime());
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
+ }
+}
+
+void tst_QDateTime::daylightTransitions() const
+{
+ if (europeanTimeZone) {
+ // CET transitions occur at 01:00:00 UTC on last Sunday in March and October
+ // 2011-03-27 02:00:00 CET became 03:00:00 CEST at msecs = 1301187600000
+ // 2011-10-30 03:00:00 CEST became 02:00:00 CET at msecs = 1319936400000
+ // 2012-03-25 02:00:00 CET became 03:00:00 CEST at msecs = 1332637200000
+ // 2012-10-28 03:00:00 CEST became 02:00:00 CET at msecs = 1351386000000
+ const qint64 daylight2011 = 1301187600000;
+ const qint64 standard2011 = 1319936400000;
+ const qint64 daylight2012 = 1332637200000;
+ const qint64 standard2012 = 1351386000000;
+ const qint64 msecsOneHour = 3600000;
+
+ // Test for correct behviour for StandardTime -> DaylightTime transition, i.e. missing hour
+
+ // Test setting date, time in missing hour will be invalid
+
+ QDateTime before(QDate(2012, 3, 25), QTime(1, 59, 59, 999));
+ QVERIFY(before.isValid());
+ QCOMPARE(before.date(), QDate(2012, 3, 25));
+ QCOMPARE(before.time(), QTime(1, 59, 59, 999));
+ QCOMPARE(before.toMSecsSinceEpoch(), daylight2012 - 1);
+
+ QDateTime missing(QDate(2012, 3, 25), QTime(2, 0, 0));
+ QVERIFY(!missing.isValid());
+ QCOMPARE(missing.date(), QDate(2012, 3, 25));
+ QCOMPARE(missing.time(), QTime(2, 0, 0));
+
+ QDateTime after(QDate(2012, 3, 25), QTime(3, 0, 0));
+ QVERIFY(after.isValid());
+ QCOMPARE(after.date(), QDate(2012, 3, 25));
+ QCOMPARE(after.time(), QTime(3, 0, 0));
+ QCOMPARE(after.toMSecsSinceEpoch(), daylight2012);
+
+ // Test round-tripping of msecs
+
+ before.setMSecsSinceEpoch(daylight2012 - 1);
+ QVERIFY(before.isValid());
+ QCOMPARE(before.date(), QDate(2012, 3, 25));
+ QCOMPARE(before.time(), QTime(1, 59, 59, 999));
+ QCOMPARE(before.toMSecsSinceEpoch(), daylight2012 -1);
+
+ after.setMSecsSinceEpoch(daylight2012);
+ QVERIFY(after.isValid());
+ QCOMPARE(after.date(), QDate(2012, 3, 25));
+ QCOMPARE(after.time(), QTime(3, 0, 0));
+ QCOMPARE(after.toMSecsSinceEpoch(), daylight2012);
+
+ // Test changing time spec re-validates the date/time
+
+ QDateTime utc(QDate(2012, 3, 25), QTime(2, 00, 0), Qt::UTC);
+ QVERIFY(utc.isValid());
+ QCOMPARE(utc.date(), QDate(2012, 3, 25));
+ QCOMPARE(utc.time(), QTime(2, 0, 0));
+ utc.setTimeSpec(Qt::LocalTime);
+ QVERIFY(!utc.isValid());
+ QCOMPARE(utc.date(), QDate(2012, 3, 25));
+ QCOMPARE(utc.time(), QTime(2, 0, 0));
+ utc.setTimeSpec(Qt::UTC);
+ QVERIFY(utc.isValid());
+ QCOMPARE(utc.date(), QDate(2012, 3, 25));
+ QCOMPARE(utc.time(), QTime(2, 0, 0));
+
+ // Test date maths, if result falls in missing hour then becomes next hour
+
+ QDateTime test(QDate(2011, 3, 25), QTime(2, 0, 0));
+ QVERIFY(test.isValid());
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 3, 25));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+ test = QDateTime(QDate(2012, 2, 25), QTime(2, 0, 0));
+ QVERIFY(test.isValid());
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 3, 25));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+ test = QDateTime(QDate(2012, 3, 24), QTime(2, 0, 0));
+ QVERIFY(test.isValid());
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 3, 25));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+ test = QDateTime(QDate(2012, 3, 25), QTime(1, 0, 0));
+ QVERIFY(test.isValid());
+ QCOMPARE(test.toMSecsSinceEpoch(), daylight2012 - msecsOneHour);
+ test = test.addMSecs(msecsOneHour);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 3, 25));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+ QCOMPARE(test.toMSecsSinceEpoch(), daylight2012);
+
+
+ // Test for correct behviour for DaylightTime -> StandardTime transition, i.e. second occurrence
+
+ // Test setting date and time in first and second occurrence will be valid
+
+ // 1 hour before transition is 2:00:00 FirstOccurrence
+ QDateTime hourBefore(QDate(2012, 10, 28), QTime(2, 0, 0));
+ QVERIFY(hourBefore.isValid());
+ QCOMPARE(hourBefore.date(), QDate(2012, 10, 28));
+ QCOMPARE(hourBefore.time(), QTime(2, 0, 0));
+#ifdef Q_OS_WIN
+ // Windows uses SecondOccurrence
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(hourBefore.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // 1 msec before transition is 2:59:59.999 FirstOccurrence
+ QDateTime msecBefore(QDate(2012, 10, 28), QTime(2, 59, 59, 999));
+ QVERIFY(msecBefore.isValid());
+ QCOMPARE(msecBefore.date(), QDate(2012, 10, 28));
+ QCOMPARE(msecBefore.time(), QTime(2, 59, 59, 999));
+#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
+ // Win and Mac uses SecondOccurrence here
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(msecBefore.toMSecsSinceEpoch(), standard2012 - 1);
+
+ // At transition is 2:00:00 SecondOccurrence
+ QDateTime atTran(QDate(2012, 10, 28), QTime(2, 0, 0));
+ QVERIFY(atTran.isValid());
+ QCOMPARE(atTran.date(), QDate(2012, 10, 28));
+ QCOMPARE(atTran.time(), QTime(2, 0, 0));
+#ifndef Q_OS_WIN
+ // Windows uses SecondOccurrence
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(atTran.toMSecsSinceEpoch(), standard2012);
+
+ // 59:59.999 after transition is 2:59:59.999 SecondOccurrence
+ QDateTime afterTran(QDate(2012, 10, 28), QTime(2, 59, 59, 999));
+ QVERIFY(afterTran.isValid());
+ QCOMPARE(afterTran.date(), QDate(2012, 10, 28));
+ QCOMPARE(afterTran.time(), QTime(2, 59, 59, 999));
+#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC)
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_UNIX
+ QCOMPARE(afterTran.toMSecsSinceEpoch(), standard2012 + msecsOneHour - 1);
+
+ // 1 hour after transition is 3:00:00 FirstOccurrence
+ QDateTime hourAfter(QDate(2012, 10, 28), QTime(3, 0, 0));
+ QVERIFY(hourAfter.isValid());
+ QCOMPARE(hourAfter.date(), QDate(2012, 10, 28));
+ QCOMPARE(hourAfter.time(), QTime(3, 0, 0));
+ QCOMPARE(hourAfter.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ // Test round-tripping of msecs
+
+ // 1 hour before transition is 2:00:00 FirstOccurrence
+ hourBefore.setMSecsSinceEpoch(standard2012 - msecsOneHour);
+ QVERIFY(hourBefore.isValid());
+ QCOMPARE(hourBefore.date(), QDate(2012, 10, 28));
+ QCOMPARE(hourBefore.time(), QTime(2, 0, 0));
+#ifndef Q_OS_MAC
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(hourBefore.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // 1 msec before transition is 2:59:59.999 FirstOccurrence
+ msecBefore.setMSecsSinceEpoch(standard2012 - 1);
+ QVERIFY(msecBefore.isValid());
+ QCOMPARE(msecBefore.date(), QDate(2012, 10, 28));
+ QCOMPARE(msecBefore.time(), QTime(2, 59, 59, 999));
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+ QCOMPARE(msecBefore.toMSecsSinceEpoch(), standard2012 - 1);
+
+ // At transition is 2:00:00 SecondOccurrence
+ atTran.setMSecsSinceEpoch(standard2012);
+ QVERIFY(atTran.isValid());
+ QCOMPARE(atTran.date(), QDate(2012, 10, 28));
+ QCOMPARE(atTran.time(), QTime(2, 0, 0));
+#ifdef Q_OS_MAC
+ // Mac defaults to FirstOccurrence here
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(atTran.toMSecsSinceEpoch(), standard2012);
+
+ // 59:59.999 after transition is 2:59:59.999 SecondOccurrence
+ afterTran.setMSecsSinceEpoch(standard2012 + msecsOneHour - 1);
+ QVERIFY(afterTran.isValid());
+ QCOMPARE(afterTran.date(), QDate(2012, 10, 28));
+ QCOMPARE(afterTran.time(), QTime(2, 59, 59, 999));
+ QCOMPARE(afterTran.toMSecsSinceEpoch(), standard2012 + msecsOneHour - 1);
+
+ // 1 hour after transition is 3:00:00 FirstOccurrence
+ hourAfter.setMSecsSinceEpoch(standard2012 + msecsOneHour);
+ QVERIFY(hourAfter.isValid());
+ QCOMPARE(hourAfter.date(), QDate(2012, 10, 28));
+ QCOMPARE(hourAfter.time(), QTime(3, 0, 0));
+ QCOMPARE(hourAfter.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ // Test date maths, result is always FirstOccurrence
+
+ // Add year to get to tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 28), QTime(2, 0, 0));
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+#ifndef Q_OS_MAC
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // Add year to get to after tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 28), QTime(3, 0, 0));
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ // Add year to tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0));
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 30));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add year to tran SecondOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0)); // TODO SecondOccurrence
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 30));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add year to after tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(3, 0, 0));
+ test = test.addYears(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 30));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+
+ // Add month to get to tran FirstOccurrence
+ test = QDateTime(QDate(2012, 9, 28), QTime(2, 0, 0));
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+#ifndef Q_OS_MAC
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // Add month to get to after tran FirstOccurrence
+ test = QDateTime(QDate(2012, 9, 28), QTime(3, 0, 0));
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ // Add month to tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0));
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 11, 30));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add month to tran SecondOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0)); // TODO SecondOccurrence
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 11, 30));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add month to after tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(3, 0, 0));
+ test = test.addMonths(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 11, 30));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+
+ // Add day to get to tran FirstOccurrence
+ test = QDateTime(QDate(2012, 10, 27), QTime(2, 0, 0));
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+#ifndef Q_OS_MAC
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // Add day to get to after tran FirstOccurrence
+ test = QDateTime(QDate(2012, 10, 27), QTime(3, 0, 0));
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ // Add day to tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0));
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 10, 31));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add day to tran SecondOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(2, 0, 0)); // TODO SecondOccurrence
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 10, 31));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+
+ // Add day to after tran FirstOccurrence
+ test = QDateTime(QDate(2011, 10, 30), QTime(3, 0, 0));
+ test = test.addDays(1);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2011, 10, 31));
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+
+
+ // Add hour to get to tran FirstOccurrence
+ test = QDateTime(QDate(2012, 10, 28), QTime(1, 0, 0));
+ test = test.addMSecs(msecsOneHour);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+#ifdef Q_OS_WIN
+ // Windows uses SecondOccurrence
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 - msecsOneHour);
+
+ // Add hour to tran FirstOccurrence to get to tran SecondOccurrence
+ test = QDateTime(QDate(2012, 10, 28), QTime(2, 0, 0));
+ test = test.addMSecs(msecsOneHour);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+#ifdef Q_OS_WIN
+ // Windows uses SecondOccurrence
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(test.time(), QTime(2, 0, 0));
+#ifndef Q_OS_MAC
+ // Windows uses SecondOccurrence
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_MAC
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012);
+
+ // Add hour to tran SecondOccurrence to get to after tran FirstOccurrence
+ test = QDateTime(QDate(2012, 10, 28), QTime(2, 0, 0)); // TODO SecondOccurrence
+ test = test.addMSecs(msecsOneHour);
+ QVERIFY(test.isValid());
+ QCOMPARE(test.date(), QDate(2012, 10, 28));
+#ifndef Q_OS_WIN
+ // Mac uses FirstOccurrence
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(test.time(), QTime(3, 0, 0));
+#ifndef Q_OS_WIN
+ // Mac uses FirstOccurrence
+ // Linux mktime bug uses last calculation
+ QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(test.toMSecsSinceEpoch(), standard2012 + msecsOneHour);
+
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QDateTime)
#include "tst_qdatetime.moc"
diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
index fa747b3c18..3348b49110 100644
--- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
+++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
@@ -730,14 +730,16 @@ double static inline _fast_cbrt(double d)
void tst_QEasingCurve::testCbrtDouble()
{
- const qreal errorBound = 0.0001;
+ const double errorBound = 0.0001;
for (int i = 0; i < 100000; i++) {
double d = double(i) / 1000.0;
double t = _fast_cbrt(d);
const double t_cubic = t * t * t;
- t = t * (t_cubic + d + d) / (t_cubic + t_cubic + d);
+ const double f = t_cubic + t_cubic + d;
+ if (f != 0.0)
+ t = t * (t_cubic + d + d) / f;
double expected = pow(d, 1.0/3.0);
@@ -754,14 +756,16 @@ void tst_QEasingCurve::testCbrtDouble()
void tst_QEasingCurve::testCbrtFloat()
{
- const qreal errorBound = 0.0005;
+ const float errorBound = 0.0005;
- for (int i = 1; i < 100000; i++) {
+ for (int i = 0; i < 100000; i++) {
float f = float(i) / 1000.0f;
float t = _fast_cbrt(f);
const float t_cubic = t * t * t;
- t = t * (t_cubic + f + f) / (t_cubic + t_cubic + f);
+ const float fac = t_cubic + t_cubic + f;
+ if (fac != 0.0f)
+ t = t * (t_cubic + f + f) / fac;
float expected = pow(f, float(1.0/3.0));
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index 71428310b8..af1c7aed15 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -78,6 +78,7 @@ private slots:
void qthash_data();
void qthash();
+ void eraseValidIteratorOnSharedHash();
};
struct Foo {
@@ -1352,5 +1353,34 @@ void tst_QHash::qthash()
QTEST(result, "hash");
}
+void tst_QHash::eraseValidIteratorOnSharedHash()
+{
+ QHash<int, int> a, b;
+ a.insert(10, 10);
+ a.insertMulti(10, 25);
+ a.insertMulti(10, 30);
+ a.insert(20, 20);
+ a.insert(40, 40);
+
+ QHash<int, int>::iterator i = a.begin();
+ while (i.value() != 25)
+ ++i;
+
+ b = a;
+ a.erase(i);
+
+ QCOMPARE(b.size(), 5);
+ QCOMPARE(a.size(), 4);
+
+ for (i = a.begin(); i != a.end(); ++i)
+ QVERIFY(i.value() != 25);
+
+ int itemsWith10 = 0;
+ for (i = b.begin(); i != b.end(); ++i)
+ itemsWith10 += (i.key() == 10);
+
+ QCOMPARE(itemsWith10, 3);
+}
+
QTEST_APPLESS_MAIN(tst_QHash)
#include "tst_qhash.moc"
diff --git a/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro b/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro
new file mode 100644
index 0000000000..439bf03707
--- /dev/null
+++ b/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase parallel_test
+TARGET = tst_qlinkedlist
+QT = core testlib
+SOURCES = tst_qlinkedlist.cpp
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
new file mode 100644
index 0000000000..49b32d5534
--- /dev/null
+++ b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
@@ -0,0 +1,1100 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QLinkedList>
+
+struct Movable
+{
+ Movable(char input = 'j') : i(input), state(Constructed)
+ {
+ ++liveCount;
+ }
+ Movable(const Movable &other)
+ : i(other.i)
+ , state(Constructed)
+ {
+ check(other.state, Constructed);
+ ++liveCount;
+ }
+
+ ~Movable()
+ {
+ check(state, Constructed);
+ i = 0;
+ --liveCount;
+ state = Destructed;
+ }
+
+ bool operator ==(const Movable &other) const
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ return i == other.i;
+ }
+
+ Movable &operator=(const Movable &other)
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ return *this;
+ }
+ char i;
+
+ static int getLiveCount() { return liveCount; }
+private:
+ static int liveCount;
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state;
+
+ static void check(const State state1, const State state2)
+ {
+ QCOMPARE(int(state1), int(state2));
+ }
+};
+
+int Movable::liveCount = 0;
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Movable);
+
+Q_DECLARE_METATYPE(QLinkedList<int>);
+
+
+int qHash(const Movable& movable)
+{
+ return qHash(movable.i);
+}
+
+struct Complex
+{
+ Complex(int val = 0)
+ : value(val)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex(Complex const &other)
+ : value(other.value)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex &operator=(Complex const &other)
+ {
+ check(); other.check();
+
+ value = other.value;
+ return *this;
+ }
+
+ ~Complex()
+ {
+ --liveCount;
+ check();
+ }
+
+ operator int() const { return value; }
+
+ bool operator==(Complex const &other) const
+ {
+ check(); other.check();
+ return value == other.value;
+ }
+
+ void check() const
+ {
+ QVERIFY(this == checkSum);
+ }
+
+ static int getLiveCount() { return liveCount; }
+private:
+ static int liveCount;
+
+ int value;
+ void *checkSum;
+};
+
+int Complex::liveCount = 0;
+
+Q_DECLARE_METATYPE(Complex);
+
+// Tests depend on the fact that:
+Q_STATIC_ASSERT(!QTypeInfo<int>::isStatic);
+Q_STATIC_ASSERT(!QTypeInfo<int>::isComplex);
+Q_STATIC_ASSERT(!QTypeInfo<Movable>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Movable>::isComplex);
+Q_STATIC_ASSERT(QTypeInfo<Complex>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Complex>::isComplex);
+
+class tst_QLinkedList : public QObject
+{
+ Q_OBJECT
+private slots:
+ void eraseValidIteratorsOnSharedList() const;
+ void insertWithIteratorsOnSharedList() const;
+ void lengthInt() const;
+ void lengthMovable() const;
+ void lengthComplex() const;
+ void lengthSignature() const;
+ void firstInt() const;
+ void firstMovable() const;
+ void firstComplex() const;
+ void lastInt() const;
+ void lastMovable() const;
+ void lastComplex() const;
+ void beginInt() const;
+ void beginMovable() const;
+ void beginComplex() const;
+ void endInt() const;
+ void endMovable() const;
+ void endComplex() const;
+ void containsInt() const;
+ void containsMovable() const;
+ void containsComplex() const;
+ void countInt() const;
+ void countMovable() const;
+ void countComplex() const;
+ void emptyInt() const;
+ void emptyMovable() const;
+ void emptyComplex() const;
+ void endsWithInt() const;
+ void endsWithMovable() const;
+ void endsWithComplex() const;
+ void removeAllInt() const;
+ void removeAllMovable() const;
+ void removeAllComplex() const;
+ void removeOneInt() const;
+ void removeOneMovable() const;
+ void removeOneComplex() const;
+ void startsWithInt() const;
+ void startsWithMovable() const;
+ void startsWithComplex() const;
+ void takeFirstInt() const;
+ void takeFirstMovable() const;
+ void takeFirstComplex() const;
+ void takeLastInt() const;
+ void takeLastMovable() const;
+ void takeLastComplex() const;
+ void toStdListInt() const;
+ void toStdListMovable() const;
+ void toStdListComplex() const;
+ void testOperatorsInt() const;
+ void testOperatorsMovable() const;
+ void testOperatorsComplex() const;
+ void testSTLIteratorsInt() const;
+ void testSTLIteratorsMovable() const;
+ void testSTLIteratorsComplex() const;
+
+ void initializeList() const;
+
+ void constSharedNullInt() const;
+ void constSharedNullMovable() const;
+ void constSharedNullComplex() const;
+
+ void setSharableInt() const;
+private:
+ template<typename T> void length() const;
+ template<typename T> void first() const;
+ template<typename T> void last() const;
+ template<typename T> void begin() const;
+ template<typename T> void end() const;
+ template<typename T> void contains() const;
+ template<typename T> void count() const;
+ template<typename T> void empty() const;
+ template<typename T> void endsWith() const;
+ template<typename T> void move() const;
+ template<typename T> void removeAll() const;
+ template<typename T> void removeOne() const;
+ template<typename T> void startsWith() const;
+ template<typename T> void swap() const;
+ template<typename T> void takeFirst() const;
+ template<typename T> void takeLast() const;
+ template<typename T> void toStdList() const;
+ template<typename T> void value() const;
+
+ template<typename T> void testOperators() const;
+ template<typename T> void testSTLIterators() const;
+
+ template<typename T> void constSharedNull() const;
+
+ int dummyForGuard;
+};
+
+template<typename T> struct SimpleValue
+{
+ static T at(int index)
+ {
+ return values[index % maxSize];
+ }
+ static const uint maxSize = 7;
+ static const T values[maxSize];
+};
+
+template<>
+const int SimpleValue<int>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+template<>
+const Movable SimpleValue<Movable>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+template<>
+const Complex SimpleValue<Complex>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+
+// Make some macros for the tests to use in order to be slightly more readable...
+#define T_FOO SimpleValue<T>::at(0)
+#define T_BAR SimpleValue<T>::at(1)
+#define T_BAZ SimpleValue<T>::at(2)
+#define T_CAT SimpleValue<T>::at(3)
+#define T_DOG SimpleValue<T>::at(4)
+#define T_BLAH SimpleValue<T>::at(5)
+#define T_WEEE SimpleValue<T>::at(6)
+
+template<typename T>
+void tst_QLinkedList::length() const
+{
+ /* Empty list. */
+ {
+ const QLinkedList<T> list;
+ QCOMPARE(list.size(), 0);
+ }
+
+ /* One entry. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ QCOMPARE(list.size(), 1);
+ }
+
+ /* Two entries. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ list.append(T_BAR);
+ QCOMPARE(list.size(), 2);
+ }
+
+ /* Three entries. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ list.append(T_BAR);
+ list.append(T_BAZ);
+ QCOMPARE(list.size(), 3);
+ }
+}
+
+void tst_QLinkedList::eraseValidIteratorsOnSharedList() const
+{
+ QLinkedList<int> a, b;
+ a.append(5);
+ a.append(10);
+ a.append(20);
+ a.append(20);
+ a.append(20);
+ a.append(20);
+ a.append(30);
+
+ QLinkedList<int>::iterator i = a.begin();
+ ++i;
+ ++i;
+ ++i;
+ b = a;
+ QLinkedList<int>::iterator r = a.erase(i);
+ QCOMPARE(b.size(), 7);
+ QCOMPARE(a.size(), 6);
+ --r;
+ --r;
+ QCOMPARE(*r, 10); // Ensure that number 2 instance was removed;
+}
+
+void tst_QLinkedList::insertWithIteratorsOnSharedList() const
+{
+ QLinkedList<int> a, b;
+ a.append(5);
+ a.append(10);
+ a.append(20);
+ QLinkedList<int>::iterator i = a.begin();
+ ++i;
+ ++i;
+ b = a;
+
+ QLinkedList<int>::iterator i2 = a.insert(i, 15);
+ QCOMPARE(b.size(), 3);
+ QCOMPARE(a.size(), 4);
+ --i2;
+ QCOMPARE(*i2, 10);
+}
+
+void tst_QLinkedList::lengthInt() const
+{
+ length<int>();
+}
+
+void tst_QLinkedList::lengthMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ length<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::lengthComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ length<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::lengthSignature() const
+{
+ /* Constness. */
+ {
+ const QLinkedList<int> list;
+ /* The function should be const. */
+ list.size();
+ }
+}
+
+template<typename T>
+void tst_QLinkedList::first() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(list.first(), T_FOO);
+
+ // remove an item, make sure it still works
+ list.pop_front();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.first(), T_BAR);
+}
+
+void tst_QLinkedList::firstInt() const
+{
+ first<int>();
+}
+
+void tst_QLinkedList::firstMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ first<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::firstComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ first<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::last() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(list.last(), T_BAR);
+
+ // remove an item, make sure it still works
+ list.pop_back();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.last(), T_FOO);
+}
+
+void tst_QLinkedList::lastInt() const
+{
+ last<int>();
+}
+
+void tst_QLinkedList::lastMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ last<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::lastComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ last<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::begin() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(*list.begin(), T_FOO);
+
+ // remove an item, make sure it still works
+ list.pop_front();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*list.begin(), T_BAR);
+}
+
+void tst_QLinkedList::beginInt() const
+{
+ begin<int>();
+}
+
+void tst_QLinkedList::beginMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ begin<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::beginComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ begin<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::end() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(*--list.end(), T_BAR);
+
+ // remove an item, make sure it still works
+ list.pop_back();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*--list.end(), T_FOO);
+}
+
+void tst_QLinkedList::endInt() const
+{
+ end<int>();
+}
+
+void tst_QLinkedList::endMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ end<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::endComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ end<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::contains() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QVERIFY(list.contains(T_FOO) == true);
+ QVERIFY(list.contains(T_BLAH) != true);
+
+ // add it and make sure it matches
+ list.append(T_BLAH);
+ QVERIFY(list.contains(T_BLAH) == true);
+}
+
+void tst_QLinkedList::containsInt() const
+{
+ contains<int>();
+}
+
+void tst_QLinkedList::containsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ contains<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::containsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ contains<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::count() const
+{
+ QLinkedList<T> list;
+
+ // starts empty
+ QVERIFY(list.count() == 0);
+
+ // goes up
+ list.append(T_FOO);
+ QVERIFY(list.count() == 1);
+
+ // and up
+ list.append(T_BAR);
+ QVERIFY(list.count() == 2);
+
+ // and down
+ list.pop_back();
+ QVERIFY(list.count() == 1);
+
+ // and empty. :)
+ list.pop_back();
+ QVERIFY(list.count() == 0);
+}
+
+void tst_QLinkedList::countInt() const
+{
+ count<int>();
+}
+
+void tst_QLinkedList::countMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ count<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::countComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ count<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::empty() const
+{
+ QLinkedList<T> list;
+
+ // make sure it starts empty
+ QVERIFY(list.empty());
+
+ // and doesn't stay empty
+ list.append(T_FOO);
+ QVERIFY(!list.empty());
+
+ // and goes back to being empty
+ list.pop_back();
+ QVERIFY(list.empty());
+}
+
+void tst_QLinkedList::emptyInt() const
+{
+ empty<int>();
+}
+
+void tst_QLinkedList::emptyMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ empty<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::emptyComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ empty<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::endsWith() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // test it returns correctly in both cases
+ QVERIFY(list.endsWith(T_BAZ));
+ QVERIFY(!list.endsWith(T_BAR));
+
+ // remove an item and make sure the end item changes
+ list.pop_back();
+ QVERIFY(list.endsWith(T_BAR));
+}
+
+void tst_QLinkedList::endsWithInt() const
+{
+ endsWith<int>();
+}
+
+void tst_QLinkedList::endsWithMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ endsWith<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::endsWithComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ endsWith<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::removeAll() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // remove one instance
+ list.removeAll(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
+
+ // many instances
+ list << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ;
+ list.removeAll(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
+
+ // try remove something that doesn't exist
+ list.removeAll(T_WEEE);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
+}
+
+void tst_QLinkedList::removeAllInt() const
+{
+ removeAll<int>();
+}
+
+void tst_QLinkedList::removeAllMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ removeAll<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::removeAllComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ removeAll<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::removeOne() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // middle
+ list.removeOne(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
+
+ // start
+ list.removeOne(T_FOO);
+ QCOMPARE(list, QLinkedList<T>() << T_BAZ);
+
+ // last
+ list.removeOne(T_BAZ);
+ QCOMPARE(list, QLinkedList<T>());
+
+ // make sure it really only removes one :)
+ list << T_FOO << T_FOO;
+ list.removeOne(T_FOO);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO);
+
+ // try remove something that doesn't exist
+ list.removeOne(T_WEEE);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO);
+}
+
+void tst_QLinkedList::removeOneInt() const
+{
+ removeOne<int>();
+}
+
+void tst_QLinkedList::removeOneMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ removeOne<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::removeOneComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ removeOne<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::startsWith() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // make sure it starts ok
+ QVERIFY(list.startsWith(T_FOO));
+
+ // remove an item
+ list.removeFirst();
+ QVERIFY(list.startsWith(T_BAR));
+}
+
+void tst_QLinkedList::startsWithInt() const
+{
+ startsWith<int>();
+}
+
+void tst_QLinkedList::startsWithMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ startsWith<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::startsWithComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ startsWith<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::takeFirst() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QCOMPARE(list.takeFirst(), T_FOO);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(list.takeFirst(), T_BAR);
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.takeFirst(), T_BAZ);
+ QVERIFY(list.size() == 0);
+}
+
+void tst_QLinkedList::takeFirstInt() const
+{
+ takeFirst<int>();
+}
+
+void tst_QLinkedList::takeFirstMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ takeFirst<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::takeFirstComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ takeFirst<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::takeLast() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QCOMPARE(list.takeLast(), T_BAZ);
+ QCOMPARE(list.takeLast(), T_BAR);
+ QCOMPARE(list.takeLast(), T_FOO);
+}
+
+void tst_QLinkedList::takeLastInt() const
+{
+ takeLast<int>();
+}
+
+void tst_QLinkedList::takeLastMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ takeLast<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::takeLastComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ takeLast<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::toStdList() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // yuck.
+ std::list<T> slist;
+ slist.push_back(T_FOO);
+ slist.push_back(T_BAR);
+ slist.push_back(T_BAZ);
+
+ QCOMPARE(list.toStdList(), slist);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ);
+}
+
+void tst_QLinkedList::toStdListInt() const
+{
+ toStdList<int>();
+}
+
+void tst_QLinkedList::toStdListMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ toStdList<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::toStdListComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ toStdList<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::testOperators() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QLinkedList<T> listtwo;
+ listtwo << T_FOO << T_BAR << T_BAZ;
+
+ // test equal
+ QVERIFY(list == listtwo);
+
+ // not equal
+ listtwo.append(T_CAT);
+ QVERIFY(list != listtwo);
+
+ // +=
+ list += listtwo;
+ QVERIFY(list.size() == 7);
+ QVERIFY(listtwo.size() == 4);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ
+ << T_FOO << T_BAR << T_BAZ << T_CAT);
+
+ // =
+ list = listtwo;
+ QCOMPARE(list, listtwo);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ << T_CAT);
+}
+
+void tst_QLinkedList::testOperatorsInt() const
+{
+ testOperators<int>();
+}
+
+void tst_QLinkedList::testOperatorsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ testOperators<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::testOperatorsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ testOperators<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::testSTLIterators() const
+{
+ QLinkedList<T> list;
+
+ // create a list
+ list << T_FOO << T_BAR << T_BAZ;
+ typename QLinkedList<T>::iterator it = list.begin();
+ QCOMPARE(*it, T_FOO); it++;
+ QCOMPARE(*it, T_BAR); it++;
+ QCOMPARE(*it, T_BAZ); it++;
+ QCOMPARE(it, list.end()); it--;
+
+ // walk backwards
+ QCOMPARE(*it, T_BAZ); it--;
+ QCOMPARE(*it, T_BAR); it--;
+ QCOMPARE(*it, T_FOO);
+
+ // test erase
+ it = list.erase(it);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(*it, T_BAR);
+
+ // test multiple erase
+ it = list.erase(it, it + 2);
+ QVERIFY(list.size() == 0);
+ QCOMPARE(it, list.end());
+
+ // insert again
+ it = list.insert(it, T_FOO);
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*it, T_FOO);
+
+ // insert again
+ it = list.insert(it, T_BAR);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(*it++, T_BAR);
+ QCOMPARE(*it, T_FOO);
+}
+
+void tst_QLinkedList::testSTLIteratorsInt() const
+{
+ testSTLIterators<int>();
+}
+
+void tst_QLinkedList::testSTLIteratorsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ testSTLIterators<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::testSTLIteratorsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ testSTLIterators<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::initializeList() const
+{
+#ifdef Q_COMPILER_INITIALIZER_LISTS
+ QLinkedList<int> v1 { 2, 3, 4 };
+ QCOMPARE(v1, QLinkedList<int>() << 2 << 3 << 4);
+ QCOMPARE(v1, (QLinkedList<int> { 2, 3, 4}));
+
+ QLinkedList<QLinkedList<int>> v2{ v1, { 1 }, QLinkedList<int>(), { 2, 3, 4 } };
+ QLinkedList<QLinkedList<int>> v3;
+ v3 << v1 << (QLinkedList<int>() << 1) << QLinkedList<int>() << v1;
+ QCOMPARE(v3, v2);
+#endif
+}
+
+
+template<typename T>
+void tst_QLinkedList::constSharedNull() const
+{
+ QLinkedList<T> list1;
+ list1.setSharable(false);
+ QVERIFY(list1.isDetached());
+
+ QLinkedList<T> list2;
+ list2.setSharable(true);
+ QVERIFY(!list2.isDetached());
+}
+
+void tst_QLinkedList::constSharedNullInt() const
+{
+ constSharedNull<int>();
+}
+
+void tst_QLinkedList::constSharedNullMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ constSharedNull<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::constSharedNullComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ constSharedNull<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+
+void tst_QLinkedList::setSharableInt() const
+{
+ QLinkedList<int> orglist;
+ orglist << 0 << 1 << 2 << 3 << 4 << 5;
+ int size = 6;
+
+ QLinkedList<int> list;
+ list = orglist;
+
+ QVERIFY(!list.isDetached());
+ list.setSharable(true);
+
+ QCOMPARE(list.size(), size);
+
+ {
+ QLinkedList<int> copy(list);
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ list.setSharable(false);
+ QVERIFY(list.isDetached() || list.isSharedWith(QLinkedList<int>()));
+
+ {
+ QLinkedList<int> copy(list);
+
+ QVERIFY(copy.isDetached() || copy.isSharedWith(QLinkedList<int>()));
+ QCOMPARE(copy.size(), size);
+ QCOMPARE(copy, list);
+ }
+
+ list.setSharable(true);
+
+ {
+ QLinkedList<int> copy(list);
+
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ QLinkedList<int>::const_iterator it = list.constBegin();
+ for (int i = 0; i < list.size(); ++i) {
+ QCOMPARE(int(*it), i);
+ ++it;
+ }
+
+ QCOMPARE(list.size(), size);
+}
+
+QTEST_APPLESS_MAIN(tst_QLinkedList)
+#include "tst_qlinkedlist.moc"
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
index 787aa094a8..2c9bf9d4c9 100644
--- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -276,6 +276,8 @@ private slots:
void setSharableInt() const;
void setSharableComplex_data() const;
void setSharableComplex() const;
+ void eraseValidIteratorsOnSharedList() const;
+ void insertWithValidIteratorsOnSharedList() const;
private:
template<typename T> void length() const;
template<typename T> void append() const;
@@ -1620,5 +1622,52 @@ void tst_QList::setSharableComplex() const
runSetSharableTest<Complex>();
}
+void tst_QList::eraseValidIteratorsOnSharedList() const
+{
+ QList<int> a, b;
+ a.push_back(10);
+ a.push_back(20);
+ a.push_back(30);
+ QList<int>::iterator i = a.begin();
+ ++i;
+ b = a;
+ a.erase(i);
+ QCOMPARE(b.size(), 3);
+ QCOMPARE(a.size(), 2);
+ QCOMPARE(a.at(0), 10);
+ QCOMPARE(a.at(1), 30);
+
+ a.push_back(40);
+ a.push_back(50);
+ a.push_back(60);
+ QCOMPARE(a.size(), 5);
+ i = a.begin();
+ b = a;
+ ++i;
+ QList<int>::iterator j = i;
+ ++j;
+ ++j;
+ a.erase(i, j); // remove 3 elements
+ QCOMPARE(b.size(), 5);
+ QCOMPARE(a.size(), 3);
+ QCOMPARE(a.at(0), 10);
+ QCOMPARE(a.at(1), 50);
+}
+
+void tst_QList::insertWithValidIteratorsOnSharedList() const
+{
+ QList<int> a, b;
+ a.push_back(10);
+ a.push_back(20);
+ a.push_back(30);
+ QList<int>::iterator i = a.begin();
+ ++i;
+ b = a;
+ a.insert(i, 15);
+ QCOMPARE(a.size(), b.size() + 1);
+ QCOMPARE(b.at(1), 20);
+ QCOMPARE(a.at(1), 15);
+}
+
QTEST_APPLESS_MAIN(tst_QList)
#include "tst_qlist.moc"
diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp
index 0c4dde4b1a..ea0e90a503 100644
--- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp
@@ -163,6 +163,7 @@ private slots:
void formatTime_data();
void formatDateTime();
void formatDateTime_data();
+ void formatTimeZone();
void toDateTime_data();
void toDateTime();
void negativeNumbers();
@@ -199,6 +200,7 @@ private slots:
private:
QString m_decimal, m_thousand, m_sdate, m_ldate, m_time;
QString m_sysapp;
+ bool europeanTimeZone;
#ifdef Q_OS_BLACKBERRY
int m_languageFd;
@@ -208,6 +210,11 @@ private:
tst_QLocale::tst_QLocale()
{
qRegisterMetaType<QLocale::FormatType>("QLocale::FormatType");
+
+ // Test if in Central European Time zone
+ uint x1 = QDateTime(QDate(1990, 1, 1), QTime()).toTime_t();
+ uint x2 = QDateTime(QDate(1990, 6, 1), QTime()).toTime_t();
+ europeanTimeZone = (x1 == 631148400 && x2 == 644191200);
}
void tst_QLocale::initTestCase()
@@ -1198,6 +1205,59 @@ void tst_QLocale::formatDateTime_data()
QTest::newRow("28no_NO") << "no_NO" << QDateTime()
<< "'\"yymm\"'" << "";
+ QDateTime testLongHour(QDate(1999, 12, 31), QTime(23, 59, 59, 999));
+ QDateTime testShortHour(QDate(1999, 12, 31), QTime(3, 59, 59, 999));
+ QDateTime testZeroHour(QDate(1999, 12, 31), QTime(0, 59, 59, 999));
+
+ QTest::newRow("datetime0") << "en_US" << QDateTime()
+ << QString("dd-MM-yyyy hh:mm:ss") << QString();
+ QTest::newRow("datetime1") << "en_US" << testLongHour
+ << QString("dd-'mmddyy'MM-yyyy hh:mm:ss.zzz")
+ << QString("31-mmddyy12-1999 23:59:59.999");
+ QTest::newRow("datetime2") << "en_US" << testLongHour
+ << QString("dd-'apAP'MM-yyyy hh:mm:ss.zzz")
+ << QString("31-apAP12-1999 23:59:59.999");
+ QTest::newRow("datetime3") << "en_US" << testLongHour
+ << QString("Apdd-MM-yyyy hh:mm:ss.zzz")
+ << QString("PMp31-12-1999 11:59:59.999");
+ QTest::newRow("datetime4") << "en_US" << testLongHour
+ << QString("'ap'apdd-MM-yyyy 'AP'hh:mm:ss.zzz")
+ << QString("appm31-12-1999 AP11:59:59.999");
+ QTest::newRow("datetime5") << "en_US" << testLongHour
+ << QString("'''") << QString("'");
+ QTest::newRow("datetime6") << "en_US" << testLongHour
+ << QString("'ap") << QString("ap");
+ QTest::newRow("datetime7") << "en_US" << testLongHour
+ << QString("' ' 'hh' hh") << QString(" hh 23");
+ QTest::newRow("datetime8") << "en_US" << testLongHour
+ << QString("d'foobar'") << QString("31foobar");
+ QTest::newRow("datetime9") << "en_US" << testShortHour
+ << QString("hhhhh") << QString("03033");
+ QTest::newRow("datetime11") << "en_US" << testLongHour
+ << QString("HHHhhhAaAPap") << QString("23231111PMpmPMpm");
+ QTest::newRow("datetime12") << "en_US" << testShortHour
+ << QString("HHHhhhAaAPap") << QString("033033AMamAMam");
+ QTest::newRow("datetime13") << "en_US" << QDateTime(QDate(1974, 12, 1), QTime(14, 14, 20))
+ << QString("hh''mm''ss dd''MM''yyyy")
+ << QString("14'14'20 01'12'1974");
+ QTest::newRow("AM no p") << "en_US" << testZeroHour
+ << QString("hhAX") << QString("12AMX");
+ QTest::newRow("AM no p, x 2") << "en_US" << testShortHour
+ << QString("hhhhhaA") << QString("03033amAM");
+ QTest::newRow("am 0 hour") << "en_US" << testZeroHour
+ << QString("hAP") << QString("12AM");
+ QTest::newRow("AM zero hour") << "en_US" << testZeroHour
+ << QString("hhAP") << QString("12AM");
+ QTest::newRow("dddd") << "en_US" << testZeroHour
+ << QString("dddd") << QString("Friday");
+ QTest::newRow("ddd") << "en_US" << testZeroHour
+ << QString("ddd") << QString("Fri");
+ QTest::newRow("MMMM") << "en_US" << testZeroHour
+ << QString("MMMM") << QString("December");
+ QTest::newRow("MMM") << "en_US" << testZeroHour
+ << QString("MMM") << QString("Dec");
+ QTest::newRow("empty") << "en_US" << testZeroHour
+ << QString("") << QString("");
}
void tst_QLocale::formatDateTime()
@@ -1211,6 +1271,46 @@ void tst_QLocale::formatDateTime()
QCOMPARE(l.toString(dateTime, format), result);
}
+void tst_QLocale::formatTimeZone()
+{
+ QLocale enUS("en_US");
+
+ QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60);
+ QCOMPARE(enUS.toString(dt1, "t"), QString("UTC+01:00"));
+
+ QDateTime dt2(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, -60 * 60);
+ QCOMPARE(enUS.toString(dt2, "t"), QString("UTC-01:00"));
+
+ QDateTime dt3(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::UTC);
+ QCOMPARE(enUS.toString(dt3, "t"), QString("UTC"));
+
+ // LocalTime should vary
+ if (europeanTimeZone) {
+ // Time definitely in Standard Time
+ QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime);
+#ifdef Q_OS_WIN
+ QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(enUS.toString(dt4, "t"), QString("CET"));
+
+ // Time definitely in Daylight Time
+ QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime);
+#ifdef Q_OS_WIN
+ QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue);
+#endif // Q_OS_WIN
+ QCOMPARE(enUS.toString(dt5, "t"), QString("CEST"));
+ } else {
+ QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
+ }
+
+ // Current datetime should return current abbreviation
+ QCOMPARE(enUS.toString(QDateTime::currentDateTime(), "t"),
+ QDateTime::currentDateTime().timeZoneAbbreviation());
+
+ // Time on its own will always be current local time zone
+ QCOMPARE(enUS.toString(QTime(1, 2, 3), "t"), QDateTime::currentDateTime().timeZoneAbbreviation());
+}
+
void tst_QLocale::toDateTime_data()
{
QTest::addColumn<QString>("localeName");
diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
index 0742f19a5e..dea657f842 100644
--- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp
+++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
@@ -59,6 +59,7 @@ private slots:
void count();
void clear();
void beginEnd();
+ void firstLast();
void key();
void swap();
@@ -87,6 +88,7 @@ private slots:
void initializerList();
void testInsertWithHint();
void testInsertMultiWithHint();
+ void eraseValidIteratorOnSharedMap();
};
typedef QMap<QString, QString> StringMap;
@@ -376,6 +378,34 @@ void tst_QMap::beginEnd()
QVERIFY( map.constBegin() != map2.constBegin() );
}
+void tst_QMap::firstLast()
+{
+ // sample string->string map
+ StringMap map;
+ map.insert("0", "a");
+ map.insert("1", "b");
+ map.insert("5", "e");
+
+ QCOMPARE(map.firstKey(), QStringLiteral("0"));
+ QCOMPARE(map.lastKey(), QStringLiteral("5"));
+ QCOMPARE(map.first(), QStringLiteral("a"));
+ QCOMPARE(map.last(), QStringLiteral("e"));
+
+ // const map
+ const StringMap const_map = map;
+ QCOMPARE(map.firstKey(), const_map.firstKey());
+ QCOMPARE(map.lastKey(), const_map.lastKey());
+ QCOMPARE(map.first(), const_map.first());
+ QCOMPARE(map.last(), const_map.last());
+
+ map.take(map.firstKey());
+ QCOMPARE(map.firstKey(), QStringLiteral("1"));
+ QCOMPARE(map.lastKey(), QStringLiteral("5"));
+
+ map.take(map.lastKey());
+ QCOMPARE(map.lastKey(), map.lastKey());
+}
+
void tst_QMap::key()
{
{
@@ -1289,6 +1319,62 @@ void tst_QMap::testInsertMultiWithHint()
QCOMPARE(map.size(), 14);
}
+void tst_QMap::eraseValidIteratorOnSharedMap()
+{
+ QMap<int, int> a, b;
+ a.insert(10, 10);
+ a.insertMulti(10, 40);
+ a.insertMulti(10, 25);
+ a.insertMulti(10, 30);
+ a.insert(20, 20);
+
+ QMap<int, int>::iterator i = a.begin();
+ while (i.value() != 25)
+ ++i;
+
+ b = a;
+ a.erase(i);
+
+ QCOMPARE(b.size(), 5);
+ QCOMPARE(a.size(), 4);
+
+ for (i = a.begin(); i != a.end(); ++i)
+ QVERIFY(i.value() != 25);
+
+ int itemsWith10 = 0;
+ for (i = b.begin(); i != b.end(); ++i)
+ itemsWith10 += (i.key() == 10);
+
+ QCOMPARE(itemsWith10, 4);
+
+ // Border cases
+ QMap <QString, QString> ms1, ms2, ms3;
+ ms1.insert("foo", "bar");
+ ms1.insertMulti("foo", "quux");
+ ms1.insertMulti("foo", "bar");
+
+ QMap <QString, QString>::iterator si = ms1.begin();
+ ms2 = ms1;
+ ms1.erase(si);
+ si = ms1.begin();
+ QCOMPARE(si.value(), QString("quux"));
+ ++si;
+ QCOMPARE(si.value(), QString("bar"));
+
+ si = ms2.begin();
+ ++si;
+ ++si;
+ ms3 = ms2;
+ ms2.erase(si);
+ si = ms2.begin();
+ QCOMPARE(si.value(), QString("bar"));
+ ++si;
+ QCOMPARE(si.value(), QString("quux"));
+
+ QCOMPARE(ms1.size(), 2);
+ QCOMPARE(ms2.size(), 2);
+ QCOMPARE(ms3.size(), 3);
+}
QTEST_APPLESS_MAIN(tst_QMap)
#include "tst_qmap.moc"
diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
index 0c76faf613..d786d1a2ce 100644
--- a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
@@ -79,6 +79,7 @@ static QString makespec()
QT_BEGIN_NAMESPACE
namespace QTest {
+#ifndef QT_NO_PROCESS
class QExternalProcess: public QProcess
{
protected:
@@ -99,6 +100,7 @@ namespace QTest {
}
#endif
};
+#endif // !QT_NO_PROCESS
class QExternalTestPrivate
{
@@ -565,6 +567,7 @@ namespace QTest {
bool QExternalTestPrivate::runQmake()
{
+#ifndef QT_NO_PROCESS
if (temporaryDirPath.isEmpty())
qWarning() << "Temporary directory is expected to be non-empty";
@@ -607,10 +610,16 @@ namespace QTest {
}
return ok && exitCode == 0;
+#else // QT_NO_PROCESS
+ return false;
+#endif // QT_NO_PROCESS
}
bool QExternalTestPrivate::runMake(Target target)
{
+#ifdef QT_NO_PROCESS
+ return false;
+#else
if (temporaryDirPath.isEmpty())
qWarning() << "Temporary directory is expected to be non-empty";
@@ -666,6 +675,7 @@ namespace QTest {
std_err += make.readAllStandardError();
return ok;
+#endif // !QT_NO_PROCESS
}
bool QExternalTestPrivate::commonSetup(const QByteArray &body)
diff --git a/tests/auto/corelib/tools/qstring/qstring.pro b/tests/auto/corelib/tools/qstring/qstring.pro
index 547dc14647..971e2fb782 100644
--- a/tests/auto/corelib/tools/qstring/qstring.pro
+++ b/tests/auto/corelib/tools/qstring/qstring.pro
@@ -5,3 +5,8 @@ SOURCES = tst_qstring.cpp
DEFINES += QT_NO_CAST_TO_ASCII
contains(QT_CONFIG,icu):DEFINES += QT_USE_ICU
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+mac {
+ OBJECTIVE_SOURCES += tst_qstring_mac.mm
+ LIBS += -framework Foundation
+}
diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp
index e7ad52a257..0148ba6d03 100644
--- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp
+++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp
@@ -170,6 +170,7 @@ private slots:
void constructorQByteArray_data();
void constructorQByteArray();
void STL();
+ void macTypes();
void isEmpty();
void isNull();
void acc_01();
@@ -939,6 +940,16 @@ void tst_QString::STL()
QCOMPARE(stlStr, s.toStdWString());
}
+void tst_QString::macTypes()
+{
+#ifndef Q_OS_MAC
+ QSKIP("This is a Mac-only test");
+#else
+ extern void tst_QString_macTypes(); // in qstring_mac.mm
+ tst_QString_macTypes();
+#endif
+}
+
void tst_QString::truncate()
{
QString e("String E");
diff --git a/tests/auto/corelib/tools/qstring/tst_qstring_mac.mm b/tests/auto/corelib/tools/qstring/tst_qstring_mac.mm
new file mode 100644
index 0000000000..9061b6c39d
--- /dev/null
+++ b/tests/auto/corelib/tools/qstring/tst_qstring_mac.mm
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** 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.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: 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
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+void tst_QString_macTypes()
+{
+ // QString <-> CFString
+ {
+ QString qtString("test string");
+ const CFStringRef cfString = qtString.toCFString();
+ QCOMPARE(QString::fromCFString(cfString), qtString);
+ CFRelease(cfString);
+ }
+ {
+ QString qtString("test string");
+ const CFStringRef cfString = qtString.toCFString();
+ QString qtStringCopy(qtString);
+ qtString = qtString.toUpper(); // modify
+ QCOMPARE(QString::fromCFString(cfString), qtStringCopy);
+ }
+ // QString <-> NSString
+ {
+ QString qtString("test string");
+ const NSString *nsString = qtString.toNSString();
+ QCOMPARE(QString::fromNSString(nsString), qtString);
+ [nsString release];
+ }
+ {
+ QString qtString("test string");
+ const NSString *nsString = qtString.toNSString();
+ QString qtStringCopy(qtString);
+ qtString = qtString.toUpper(); // modify
+ QCOMPARE(QString::fromNSString(nsString), qtStringCopy);
+ [nsString release];
+ }
+}
diff --git a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp b/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp
index 1045d5929f..7bbcee8ab2 100644
--- a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp
+++ b/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp
@@ -88,6 +88,9 @@ private slots:
void integer_conversion_data();
void integer_conversion();
void trimmed();
+ void left();
+ void right();
+ void mid();
};
static QStringRef emptyRef()
@@ -1794,6 +1797,145 @@ void tst_QStringRef::trimmed()
QCOMPARE(b.trimmed().compare(QStringLiteral("a")), 0);
}
+void tst_QStringRef::left()
+{
+ QString originalString = "OrginalString~";
+ QStringRef ref = originalString.leftRef(originalString.size() - 1);
+ QCOMPARE(ref.toString(), QStringLiteral("OrginalString"));
+
+ QVERIFY(ref.left(0).toString().isEmpty());
+ QCOMPARE(ref.left(ref.size()).toString(), QStringLiteral("OrginalString"));
+
+ QStringRef nullRef;
+ QVERIFY(nullRef.isNull());
+ QVERIFY(nullRef.left(3).toString().isEmpty());
+ QVERIFY(nullRef.left(0).toString().isEmpty());
+ QVERIFY(nullRef.left(-1).toString().isEmpty());
+
+ QStringRef emptyRef(&originalString, 0, 0);
+ QVERIFY(emptyRef.isEmpty());
+ QVERIFY(emptyRef.left(3).toString().isEmpty());
+ QVERIFY(emptyRef.left(0).toString().isEmpty());
+ QVERIFY(emptyRef.left(-1).toString().isEmpty());
+
+ QCOMPARE(ref.left(-1), ref);
+ QCOMPARE(ref.left(100), ref);
+}
+
+void tst_QStringRef::right()
+{
+ QString originalString = "~OrginalString";
+ QStringRef ref = originalString.rightRef(originalString.size() - 1);
+ QCOMPARE(ref.toString(), QLatin1String("OrginalString"));
+
+ QCOMPARE(ref.right(ref.size() - 6).toString(), QLatin1String("String"));
+ QCOMPARE(ref.right(ref.size()).toString(), QLatin1String("OrginalString"));
+ QCOMPARE(ref.right(0).toString(), QLatin1String("OrginalString"));
+
+ QStringRef nullRef;
+ QVERIFY(nullRef.isNull());
+ QVERIFY(nullRef.right(3).toString().isEmpty());
+ QVERIFY(nullRef.right(0).toString().isEmpty());
+ QVERIFY(nullRef.right(-1).toString().isEmpty());
+
+ QStringRef emptyRef(&originalString, 0, 0);
+ QVERIFY(emptyRef.isEmpty());
+ QVERIFY(emptyRef.right(3).toString().isEmpty());
+ QVERIFY(emptyRef.right(0).toString().isEmpty());
+ QVERIFY(emptyRef.right(-1).toString().isEmpty());
+
+ QCOMPARE(ref.right(-1), ref);
+ QCOMPARE(ref.right(100), ref);
+}
+
+void tst_QStringRef::mid()
+{
+ QString orig = QStringLiteral("~ABCDEFGHIEfGEFG~"); // 15 + 2 chars
+ QStringRef a = orig.midRef(1, 15);
+ QCOMPARE(a.size(), orig.size() - 2);
+
+ QCOMPARE(a.mid(3,3).toString(),(QString)"DEF");
+ QCOMPARE(a.mid(0,0).toString(),(QString)"");
+ QVERIFY(!a.mid(15,0).toString().isNull());
+ QVERIFY(a.mid(15,0).toString().isEmpty());
+ QVERIFY(!a.mid(15,1).toString().isNull());
+ QVERIFY(a.mid(15,1).toString().isEmpty());
+ QVERIFY(a.mid(9999).toString().isEmpty());
+ QVERIFY(a.mid(9999,1).toString().isEmpty());
+
+ QCOMPARE(a.mid(-1, 6), a.mid(0, 5));
+ QVERIFY(a.mid(-100, 6).isEmpty());
+ QVERIFY(a.mid(INT_MIN, 0).isEmpty());
+ QCOMPARE(a.mid(INT_MIN, -1), a);
+ QVERIFY(a.mid(INT_MIN, INT_MAX).isNull());
+ QVERIFY(a.mid(INT_MIN + 1, INT_MAX).isEmpty());
+ QCOMPARE(a.mid(INT_MIN + 2, INT_MAX), a.left(1));
+ QCOMPARE(a.mid(INT_MIN + a.size() + 1, INT_MAX), a);
+ QVERIFY(a.mid(INT_MAX).isNull());
+ QVERIFY(a.mid(INT_MAX, INT_MAX).isNull());
+ QCOMPARE(a.mid(-5, INT_MAX), a);
+ QCOMPARE(a.mid(-1, INT_MAX), a);
+ QCOMPARE(a.mid(0, INT_MAX), a);
+ QCOMPARE(a.mid(1, INT_MAX).toString(), QString("BCDEFGHIEfGEFG"));
+ QCOMPARE(a.mid(5, INT_MAX).toString(), QString("FGHIEfGEFG"));
+ QVERIFY(a.mid(20, INT_MAX).isNull());
+ QCOMPARE(a.mid(-1, -1), a);
+
+ QStringRef nullRef;
+ QVERIFY(nullRef.mid(3,3).toString().isEmpty());
+ QVERIFY(nullRef.mid(0,0).toString().isEmpty());
+ QVERIFY(nullRef.mid(9999,0).toString().isEmpty());
+ QVERIFY(nullRef.mid(9999,1).toString().isEmpty());
+
+ QVERIFY(nullRef.mid(-1, 6).isNull());
+ QVERIFY(nullRef.mid(-100, 6).isNull());
+ QVERIFY(nullRef.mid(INT_MIN, 0).isNull());
+ QVERIFY(nullRef.mid(INT_MIN, -1).isNull());
+ QVERIFY(nullRef.mid(INT_MIN, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(INT_MIN + 1, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(INT_MIN + 2, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(INT_MIN + nullRef.size() + 1, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(INT_MAX).isNull());
+ QVERIFY(nullRef.mid(INT_MAX, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(-5, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(-1, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(0, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(1, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(5, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(20, INT_MAX).isNull());
+ QVERIFY(nullRef.mid(-1, -1).isNull());
+
+ QString ninePineapples = "~Nine pineapples~";
+ QStringRef x = ninePineapples.midRef(1, ninePineapples.size() - 1);
+ QCOMPARE(x.mid(5, 4).toString(), QString("pine"));
+ QCOMPARE(x.mid(5).toString(), QString("pineapples~"));
+
+ QCOMPARE(x.mid(-1, 6), x.mid(0, 5));
+ QVERIFY(x.mid(-100, 6).isEmpty());
+ QVERIFY(x.mid(INT_MIN, 0).isEmpty());
+ QCOMPARE(x.mid(INT_MIN, -1).toString(), x.toString());
+ QVERIFY(x.mid(INT_MIN, INT_MAX).isNull());
+ QVERIFY(x.mid(INT_MIN + 1, INT_MAX).isEmpty());
+ QCOMPARE(x.mid(INT_MIN + 2, INT_MAX), x.left(1));
+ QCOMPARE(x.mid(INT_MIN + x.size() + 1, INT_MAX).toString(), x.toString());
+ QVERIFY(x.mid(INT_MAX).isNull());
+ QVERIFY(x.mid(INT_MAX, INT_MAX).isNull());
+ QCOMPARE(x.mid(-5, INT_MAX).toString(), x.toString());
+ QCOMPARE(x.mid(-1, INT_MAX).toString(), x.toString());
+ QCOMPARE(x.mid(0, INT_MAX), x);
+ QCOMPARE(x.mid(1, INT_MAX).toString(), QString("ine pineapples~"));
+ QCOMPARE(x.mid(5, INT_MAX).toString(), QString("pineapples~"));
+ QVERIFY(x.mid(20, INT_MAX).isNull());
+ QCOMPARE(x.mid(-1, -1), x);
+
+ QStringRef emptyRef(&ninePineapples, 0, 0);
+ QVERIFY(emptyRef.mid(1).isEmpty());
+ QVERIFY(emptyRef.mid(-1).isEmpty());
+ QVERIFY(emptyRef.mid(0).isEmpty());
+ QVERIFY(emptyRef.mid(0, 3).isEmpty());
+ QVERIFY(emptyRef.mid(-10, 3).isEmpty());
+}
+
QTEST_APPLESS_MAIN(tst_QStringRef)
#include "tst_qstringref.moc"
diff --git a/tests/auto/corelib/tools/qtime/tst_qtime.cpp b/tests/auto/corelib/tools/qtime/tst_qtime.cpp
index 97645ea7f6..0563111abb 100644
--- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp
+++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp
@@ -75,6 +75,8 @@ private slots:
void toStringFormat_data();
void toStringFormat();
void toStringLocale();
+ void msecsSinceStartOfDay_data();
+ void msecsSinceStartOfDay();
private:
QTime invalidTime() { return QTime(-1, -1, -1); }
@@ -575,9 +577,12 @@ void tst_QTime::fromStringDateFormat_data()
QTest::newRow("TextDate - data1") << QString("10:12:34") << Qt::TextDate << QTime(10,12,34,0);
QTest::newRow("TextDate - data2") << QString("19:03:54.998601") << Qt::TextDate << QTime(19, 3, 54, 999);
QTest::newRow("TextDate - data3") << QString("19:03:54.999601") << Qt::TextDate << QTime(19, 3, 54, 999);
+ QTest::newRow("TextDate - data4") << QString("10:12") << Qt::TextDate << QTime(10, 12, 0, 0);
QTest::newRow("TextDate - invalid, minutes") << QString::fromLatin1("23:XX:00") << Qt::TextDate << invalidTime();
+ QTest::newRow("TextDate - invalid, minute fraction") << QString::fromLatin1("23:00.123456") << Qt::TextDate << invalidTime();
QTest::newRow("TextDate - invalid, seconds") << QString::fromLatin1("23:00:XX") << Qt::TextDate << invalidTime();
QTest::newRow("TextDate - invalid, milliseconds") << QString::fromLatin1("23:01:01:XXXX") << Qt::TextDate << QTime(23, 1, 1, 0);
+ QTest::newRow("TextDate - midnight 24") << QString("24:00:00") << Qt::TextDate << QTime();
QTest::newRow("IsoDate - valid, start of day, omit seconds") << QString::fromLatin1("00:00") << Qt::ISODate << QTime(0, 0, 0);
QTest::newRow("IsoDate - valid, omit seconds") << QString::fromLatin1("22:21") << Qt::ISODate << QTime(22, 21, 0);
@@ -599,7 +604,61 @@ void tst_QTime::fromStringDateFormat_data()
QTest::newRow("IsoDate - data1") << QString("10:12:34") << Qt::ISODate << QTime(10,12,34,0);
QTest::newRow("IsoDate - data2") << QString("19:03:54.998601") << Qt::ISODate << QTime(19, 3, 54, 999);
QTest::newRow("IsoDate - data3") << QString("19:03:54.999601") << Qt::ISODate << QTime(19, 3, 54, 999);
+ QTest::newRow("IsoDate - midnight 24") << QString("24:00:00") << Qt::ISODate << QTime(0, 0, 0, 0);
QTest::newRow("IsoDate - minute fraction midnight") << QString("24:00,0") << Qt::ISODate << QTime(0, 0, 0, 0);
+
+ // Test Qt::RFC2822Date format (RFC 2822).
+ QTest::newRow("RFC 2822") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QTime(13, 24, 51);
+ QTest::newRow("RFC 2822 with day") << QString::fromLatin1("Thu, 01 Jan 1970 00:12:34 +0000")
+ << Qt::RFC2822Date << QTime(0, 12, 34);
+ // No timezone
+ QTest::newRow("RFC 2822 no timezone") << QString::fromLatin1("01 Jan 1970 00:12:34")
+ << Qt::RFC2822Date << QTime(0, 12, 34);
+ // No time specified
+ QTest::newRow("RFC 2822 date only") << QString::fromLatin1("01 Nov 2002")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 2822 with day date only") << QString::fromLatin1("Fri, 01 Nov 2002")
+ << Qt::RFC2822Date << invalidTime();
+ // Test invalid month, day, year
+ QTest::newRow("RFC 2822 invalid month name") << QString::fromLatin1("13 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QTime(13, 24, 51);
+ QTest::newRow("RFC 2822 invalid day") << QString::fromLatin1("36 Fev 1987 13:24:51 +0100")
+ << Qt::RFC2822Date << QTime(13, 24, 51);
+ QTest::newRow("RFC 2822 invalid year") << QString::fromLatin1("13 Fev 0000 13:24:51 +0100")
+ << Qt::RFC2822Date << QTime(13, 24, 51);
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 2822 invalid character at end") << QString::fromLatin1("01 Jan 2012 08:00:00 +0100!")
+ << Qt::RFC2822Date << QTime(8, 0, 0);
+ QTest::newRow("RFC 2822 invalid character at front") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 2822 invalid character both ends") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000!")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 2822 invalid character at front, 2 at back") << QString::fromLatin1("!01 Jan 2012 08:00:00 +0000..")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 2822 invalid character 2 at front") << QString::fromLatin1("!!01 Jan 2012 08:00:00 +0000")
+ << Qt::RFC2822Date << invalidTime();
+
+ // Test Qt::RFC2822Date format (RFC 850 and 1036).
+ QTest::newRow("RFC 850 and 1036") << QString::fromLatin1("Fri Feb 13 13:24:51 1987 +0100")
+ << Qt::RFC2822Date << QTime(13, 24, 51);
+ // No timezone
+ QTest::newRow("RFC 850 and 1036 no timezone") << QString::fromLatin1("Thu Jan 01 00:12:34 1970")
+ << Qt::RFC2822Date << QTime(0, 12, 34);
+ // No time specified
+ QTest::newRow("RFC 850 and 1036 date only") << QString::fromLatin1("Fri Nov 01 2002")
+ << Qt::RFC2822Date << invalidTime();
+ // Test invalid characters (should ignore invalid characters at end of string).
+ QTest::newRow("RFC 850 and 1036 invalid character at end") << QString::fromLatin1("Sun Jan 01 08:00:00 2012 +0100!")
+ << Qt::RFC2822Date << QTime(8, 0, 0);
+ QTest::newRow("RFC 850 and 1036 invalid character at front") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 850 and 1036 invalid character both ends") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000!")
+ << Qt::RFC2822Date << invalidTime();
+ QTest::newRow("RFC 850 and 1036 invalid character at front, 2 at back") << QString::fromLatin1("!Sun Jan 01 08:00:00 2012 +0000..")
+ << Qt::RFC2822Date << invalidTime();
+
+ QTest::newRow("RFC empty") << QString::fromLatin1("") << Qt::RFC2822Date << invalidTime();
}
void tst_QTime::fromStringDateFormat()
@@ -614,25 +673,28 @@ void tst_QTime::fromStringDateFormat()
void tst_QTime::toStringDateFormat_data()
{
- // Since we can't define an element of Qt::DateFormat, str1 will be the string
- // in TextDate format, and str2 will be the time in ISODate format.
-
- QTest::addColumn<QTime>("t");
- QTest::addColumn<QString>("str1");
- QTest::addColumn<QString>("str2");
-
- QTest::newRow( "data0" ) << QTime(0,0,0,0) << QString("00:00:00") << QString("00:00:00");
- QTest::newRow( "data1" ) << QTime(10,12,34,0) << QString("10:12:34") << QString("10:12:34");
+ QTest::addColumn<QTime>("time");
+ QTest::addColumn<Qt::DateFormat>("format");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("00:00:00.000") << QTime(0, 0, 0, 0) << Qt::TextDate << QString("00:00:00");
+ QTest::newRow("ISO 00:00:00.000") << QTime(0, 0, 0, 0) << Qt::ISODate << QString("00:00:00");
+ QTest::newRow("Text 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::TextDate << QString("10:12:34");
+ QTest::newRow("ISO 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::ISODate << QString("10:12:34");
+ QTest::newRow("Text 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::TextDate << QString("10:12:34");
+ QTest::newRow("ISO 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::ISODate << QString("10:12:34");
+ QTest::newRow("Text 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::TextDate << QString("10:12:34");
+ QTest::newRow("ISO 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::ISODate << QString("10:12:34");
+ QTest::newRow("RFC2822Date") << QTime(10, 12, 34, 999) << Qt::RFC2822Date << QString("10:12:34");
}
void tst_QTime::toStringDateFormat()
{
- QFETCH( QTime, t );
- QFETCH( QString, str1 );
- QFETCH( QString, str2 );
+ QFETCH(QTime, time);
+ QFETCH(Qt::DateFormat, format);
+ QFETCH(QString, expected);
- QCOMPARE( str1, t.toString( Qt::TextDate ) );
- QCOMPARE( str2, t.toString( Qt::ISODate ) );
+ QCOMPARE(time.toString(format), expected);
}
void tst_QTime::toStringFormat_data()
@@ -672,5 +734,49 @@ void tst_QTime::toStringLocale()
QLocale().toString(time, QLocale::ShortFormat));
}
+void tst_QTime::msecsSinceStartOfDay_data()
+{
+ QTest::addColumn<int>("msecs");
+ QTest::addColumn<bool>("isValid");
+ QTest::addColumn<int>("hour");
+ QTest::addColumn<int>("minute");
+ QTest::addColumn<int>("second");
+ QTest::addColumn<int>("msec");
+
+ QTest::newRow("00:00:00.000") << 0 << true
+ << 0 << 0 << 0 << 0;
+ QTest::newRow("01:00:00.001") << ((1 * 3600 * 1000) + 1) << true
+ << 1 << 0 << 0 << 1;
+ QTest::newRow("03:04:05.678") << ((3 * 3600 + 4 * 60 + 5) * 1000 + 678) << true
+ << 3 << 4 << 5 << 678;
+ QTest::newRow("23:59:59.999") << ((23 * 3600 + 59 * 60 + 59) * 1000 + 999) << true
+ << 23 << 59 << 59 << 999;
+ QTest::newRow("24:00:00.000") << ((24 * 3600) * 1000) << false
+ << -1 << -1 << -1 << -1;
+ QTest::newRow("-1 invalid") << -1 << false
+ << -1 << -1 << -1 << -1;
+}
+
+void tst_QTime::msecsSinceStartOfDay()
+{
+ QFETCH(int, msecs);
+ QFETCH(bool, isValid);
+ QFETCH(int, hour);
+ QFETCH(int, minute);
+ QFETCH(int, second);
+ QFETCH(int, msec);
+
+ QTime time = QTime::fromMSecsSinceStartOfDay(msecs);
+ QCOMPARE(time.isValid(), isValid);
+ if (msecs >= 0)
+ QCOMPARE(time.msecsSinceStartOfDay(), msecs);
+ else
+ QCOMPARE(time.msecsSinceStartOfDay(), 0);
+ QCOMPARE(time.hour(), hour);
+ QCOMPARE(time.minute(), minute);
+ QCOMPARE(time.second(), second);
+ QCOMPARE(time.msec(), msec);
+}
+
QTEST_APPLESS_MAIN(tst_QTime)
#include "tst_qtime.moc"
diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro
index f8b2437d35..fbc1b996f7 100644
--- a/tests/auto/corelib/tools/tools.pro
+++ b/tests/auto/corelib/tools/tools.pro
@@ -8,6 +8,7 @@ SUBDIRS=\
qbytedatabuffer \
qcache \
qchar \
+ qcommandlineparser \
qcontiguouscache \
qcryptographichash \
qdate \
@@ -18,6 +19,7 @@ SUBDIRS=\
qfreelist \
qhash \
qline \
+ qlinkedlist \
qlist \
qlocale \
qmap \