diff options
Diffstat (limited to 'tests/auto/corelib/tools')
19 files changed, 2969 insertions, 159 deletions
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/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..bc489f6206 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(); @@ -185,8 +191,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 +203,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 +425,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 +436,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 +474,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() @@ -501,6 +549,8 @@ void tst_QDateTime::setMSecsSinceEpoch() dt.setMSecsSinceEpoch(msecs); QCOMPARE(dt, utc); + QCOMPARE(dt.timeSpec(), Qt::UTC); + if (europeanTimeZone) { QCOMPARE(dt.toLocalTime(), european); @@ -510,6 +560,7 @@ void tst_QDateTime::setMSecsSinceEpoch() localDt.setMSecsSinceEpoch(msecs); QCOMPARE(localDt, utc); + QCOMPARE(localDt.timeSpec(), Qt::LocalTime); } QCOMPARE(dt.toMSecsSinceEpoch(), msecs); @@ -533,53 +584,174 @@ 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); + 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); + 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"); + } + + 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)); + 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)) - << QString("1978-11-09T13:28:34"); + << QString("1978-11-09T13:28:34.000"); QTest::newRow("UTC") << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) - << QString("1978-11-09T13:28:34Z"); + << QString("1978-11-09T13:28:34.000Z"); 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"); + << QString("1978-11-09T13:28:34.000+05:30"); dt.setUtcOffset(-7200); QTest::newRow("negative OffsetFromUTC") << dt - << QString("1978-11-09T13:28:34-02:00"); + << QString("1978-11-09T13:28:34.000-02:00"); QTest::newRow("invalid") << QDateTime(QDate(-1, 11, 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("2000-01-01T13:28:34.999Z"); } 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.000 2013"); + QTest::newRow("utc") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::UTC) + << QString("Wed Jan 2 01:02:03.000 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.000 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.000 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() @@ -591,7 +763,7 @@ void tst_QDateTime::toString_enumformat() QVERIFY(!str1.isEmpty()); // It's locale dependent everywhere QString str2 = dt1.toString(Qt::ISODate); - QCOMPARE(str2, QString("1995-05-20T12:34:56")); + QCOMPARE(str2, QString("1995-05-20T12:34:56.000")); QString str3 = dt1.toString(Qt::LocalDate); QVERIFY(!str3.isEmpty()); @@ -630,6 +802,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 +829,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 +867,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 +920,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() @@ -788,6 +1013,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() @@ -799,7 +1031,11 @@ void tst_QDateTime::addSecs() #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 +1053,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); @@ -903,18 +1143,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 +1209,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 +1231,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 +1569,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 +1668,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 +1751,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 +1822,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 +1847,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 +1933,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 +2109,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 +2157,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 +2336,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)); 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/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..864f90b380 100644 --- a/tests/auto/corelib/tools/qtime/tst_qtime.cpp +++ b/tests/auto/corelib/tools/qtime/tst_qtime.cpp @@ -575,9 +575,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 +602,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 +671,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.000"); + QTest::newRow("ISO 00:00:00.000") << QTime(0, 0, 0, 0) << Qt::ISODate << QString("00:00:00.000"); + QTest::newRow("Text 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::TextDate << QString("10:12:34.000"); + QTest::newRow("ISO 10:12:34.000") << QTime(10, 12, 34, 0) << Qt::ISODate << QString("10:12:34.000"); + QTest::newRow("Text 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::TextDate << QString("10:12:34.001"); + QTest::newRow("ISO 10:12:34.001") << QTime(10, 12, 34, 001) << Qt::ISODate << QString("10:12:34.001"); + QTest::newRow("Text 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::TextDate << QString("10:12:34.999"); + QTest::newRow("ISO 10:12:34.999") << QTime(10, 12, 34, 999) << Qt::ISODate << QString("10:12:34.999"); + 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() 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 \ |