diff options
Diffstat (limited to 'tests/auto/corelib/tools')
31 files changed, 2191 insertions, 100 deletions
diff --git a/tests/auto/corelib/tools/containerapisymmetry/.gitignore b/tests/auto/corelib/tools/containerapisymmetry/.gitignore new file mode 100644 index 0000000000..172ca970f2 --- /dev/null +++ b/tests/auto/corelib/tools/containerapisymmetry/.gitignore @@ -0,0 +1 @@ +tst_containerapisymmetry diff --git a/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro b/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro new file mode 100644 index 0000000000..30dc8026ef --- /dev/null +++ b/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_containerapisymmetry +SOURCES += tst_containerapisymmetry.cpp +QT = core testlib + +# This test does not work with strict iterators +DEFINES -= QT_STRICT_ITERATORS diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp new file mode 100644 index 0000000000..3b8111f1a3 --- /dev/null +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include "qbytearray.h" +#include "qlinkedlist.h" +#include "qlist.h" +#include "qstring.h" +#include "qvarlengtharray.h" +#include "qvector.h" + +#include <vector> // for reference + +class tst_ContainerApiSymmetry : public QObject +{ + Q_OBJECT + +private: + template <typename Container> + void front_back_impl() const; + +private Q_SLOTS: + void front_back_std_vector() { front_back_impl<std::vector<int>>(); } + void front_back_QVector() { front_back_impl<QVector<int>>(); } + void front_back_QList() { front_back_impl<QList<qintptr>>(); } + void front_back_QLinkedList() { front_back_impl<QLinkedList<int>>(); } + void front_back_QVarLengthArray() { front_back_impl<QVarLengthArray<int>>(); } + void front_back_QString() { front_back_impl<QString>(); } + void front_back_QStringRef() { front_back_impl<QStringRef>(); } + void front_back_QStringView() { front_back_impl<QStringView>(); } + void front_back_QLatin1String() { front_back_impl<QLatin1String>(); } + void front_back_QByteArray() { front_back_impl<QByteArray>(); } +}; + +template <typename Container> +Container make(int size) +{ + Container c; + int i = 1; + while (size--) + c.push_back(typename Container::value_type(i++)); + return c; +} + +static QString s_string = QStringLiteral("\1\2\3\4\5\6\7"); + +template <> QStringRef make(int size) { return s_string.leftRef(size); } +template <> QStringView make(int size) { return QStringView(s_string).left(size); } +template <> QLatin1String make(int size) { return QLatin1String("\1\2\3\4\5\6\7", size); } + +template <typename T> T clean(T &&t) { return std::forward<T>(t); } +inline QChar clean(QCharRef ch) { return ch; } +inline char clean(QByteRef ch) { return ch; } +inline char clean(QLatin1Char ch) { return ch.toLatin1(); } + +template <typename Container> +void tst_ContainerApiSymmetry::front_back_impl() const +{ + using V = typename Container::value_type; + auto c1 = make<Container>(1); + QCOMPARE(clean(c1.front()), V(1)); + QCOMPARE(clean(c1.back()), V(1)); + QCOMPARE(clean(qAsConst(c1).front()), V(1)); + QCOMPARE(clean(qAsConst(c1).back()), V(1)); + + auto c2 = make<Container>(2); + QCOMPARE(clean(c2.front()), V(1)); + QCOMPARE(clean(c2.back()), V(2)); + QCOMPARE(clean(qAsConst(c2).front()), V(1)); + QCOMPARE(clean(qAsConst(c2).back()), V(2)); +} + +QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry) +#include "tst_containerapisymmetry.moc" diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp index e13c2894af..72299402f0 100644 --- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp +++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp @@ -37,6 +37,7 @@ #include <qalgorithms.h> #include <QStringList> #include <QString> +#include <QRandomGenerator> #include <QVector> #define Q_TEST_PERFORMANCE 0 @@ -133,7 +134,7 @@ QVector<DataType> generateData(QString dataSetType, const int length) QVector<DataType> container; if (dataSetType == "Random") { for (int i = 0; i < length; ++i) - container.append(rand()); + container.append(QRandomGenerator::global()->generate()); } else if (dataSetType == "Ascending") { for (int i = 0; i < length; ++i) container.append(i); @@ -1082,12 +1083,12 @@ void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int) // 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()); + const quint64 input = QRandomGenerator::global()->generate64(); QTest::addRow("0x%016llx", input) << input << bitsSetInInt64(input); } else if (sizeof_T_Int >= 2) for (size_t i = 0; i < 1000 ; ++i) { - const quint32 input = qrand(); + const quint32 input = QRandomGenerator::global()->generate(); if (sizeof_T_Int >= 4) QTest::addRow("0x%08x", input) << quint64(input) << bitsSetInInt(input); else @@ -1129,7 +1130,7 @@ void tst_QAlgorithms::countTrailing_data_impl(size_t sizeof_T_Int) // and some random ones: for (uint i = 0; i < sizeof_T_Int*8; ++i) { for (uint j = 0; j < sizeof_T_Int*3; ++j) { // 3 is arbitrary - const quint64 r = quint64(qrand()) << 32 | quint32(qrand()); + const quint64 r = QRandomGenerator::global()->generate64(); const quint64 b = Q_UINT64_C(1) << i; const quint64 mask = ((~(b-1)) ^ b) & type_mask; const quint64 input = (r&mask) | b; @@ -1166,7 +1167,7 @@ void tst_QAlgorithms::countLeading_data_impl(size_t sizeof_T_Int) // and some random ones: for (uint i = 0; i < sizeof_T_Int*8; ++i) { for (uint j = 0; j < sizeof_T_Int*3; ++j) { // 3 is arbitrary - const quint64 r = quint64(qrand()) << 32 | quint32(qrand()); + const quint64 r = QRandomGenerator::global()->generate64(); const quint64 b = Q_UINT64_C(1) << i; const quint64 mask = b-1; const quint64 input = (r&mask) | b; diff --git a/tests/auto/corelib/tools/qchar/tst_qchar.cpp b/tests/auto/corelib/tools/qchar/tst_qchar.cpp index e5a6e953d3..cf4f6d21e2 100644 --- a/tests/auto/corelib/tools/qchar/tst_qchar.cpp +++ b/tests/auto/corelib/tools/qchar/tst_qchar.cpp @@ -36,6 +36,8 @@ class tst_QChar : public QObject { Q_OBJECT private slots: + void fromChar16_t(); + void fromWchar_t(); void operator_eqeq_null(); void operators_data(); void operators(); @@ -72,6 +74,33 @@ private slots: void unicodeVersion(); }; +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + +void tst_QChar::fromChar16_t() +{ +#if defined(Q_COMPILER_UNICODE_STRINGS) + QChar aUmlaut = u'\u00E4'; // German small letter a-umlaut + QCOMPARE(aUmlaut, QChar(0xE4)); + QChar replacementCharacter = u'\uFFFD'; + QCOMPARE(replacementCharacter, QChar(QChar::ReplacementCharacter)); +#else + QSKIP("This test requires C++11 char16_t support enabled in the compiler."); +#endif +} + +void tst_QChar::fromWchar_t() +{ +#if defined(Q_OS_WIN) + QChar aUmlaut = L'\u00E4'; // German small letter a-umlaut + QCOMPARE(aUmlaut, QChar(0xE4)); + QChar replacementCharacter = L'\uFFFD'; + QCOMPARE(replacementCharacter, QChar(QChar::ReplacementCharacter)); +#else + QSKIP("This is a Windows-only test."); +#endif +} + void tst_QChar::operator_eqeq_null() { { diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/tools/qdate/tst_qdate.cpp index f88eac1a9f..ff31f01d7c 100644 --- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp +++ b/tests/auto/corelib/tools/qdate/tst_qdate.cpp @@ -1490,7 +1490,7 @@ void tst_QDate::roundtrip() const void tst_QDate::qdebug() const { - QTest::ignoreMessage(QtDebugMsg, "QDate(\"\")"); + QTest::ignoreMessage(QtDebugMsg, "QDate(Invalid)"); qDebug() << QDate(); QTest::ignoreMessage(QtDebugMsg, "QDate(\"1983-08-07\")"); qDebug() << QDate(1983, 8, 7); diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 28ad2d193c..7a047c67de 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -131,6 +131,8 @@ private slots: void setOffsetFromUtc(); void toOffsetFromUtc(); + void zoneAtTime_data(); + void zoneAtTime(); void timeZoneAbbreviation(); void getDate(); @@ -1378,11 +1380,13 @@ void tst_QDateTime::toTimeSpec() QCOMPARE(utcToLocal.date(), fromLocal.date()); QCOMPARE(utcToLocal.time(), fromLocal.time()); QCOMPARE(utcToLocal.timeSpec(), Qt::LocalTime); + QCOMPARE(utcToLocal.toTimeSpec(Qt::UTC), fromUtc); QCOMPARE(localToUtc, fromUtc); QCOMPARE(localToUtc.date(), fromUtc.date()); QCOMPARE(localToUtc.time(), fromUtc.time()); QCOMPARE(localToUtc.timeSpec(), Qt::UTC); + QCOMPARE(localToUtc.toTimeSpec(Qt::LocalTime), fromLocal); QCOMPARE(utcToUtc, localToUtc); QCOMPARE(utcToUtc.date(), localToUtc.date()); @@ -1399,11 +1403,13 @@ void tst_QDateTime::toTimeSpec() QCOMPARE(utcToOffset.date(), fromUtc.date()); QCOMPARE(utcToOffset.time(), fromUtc.time()); QCOMPARE(utcToOffset.timeSpec(), Qt::UTC); + QCOMPARE(utcToOffset.toTimeSpec(Qt::UTC), fromUtc); QCOMPARE(localToOffset, fromUtc); QCOMPARE(localToOffset.date(), fromUtc.date()); QCOMPARE(localToOffset.time(), fromUtc.time()); QCOMPARE(localToOffset.timeSpec(), Qt::UTC); + QCOMPARE(localToOffset.toTimeSpec(Qt::LocalTime), fromLocal); } else { QSKIP("Not tested with timezone other than Central European (CET/CEST)"); } @@ -2277,6 +2283,9 @@ 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(); + QTest::newRow("ISO short") << QString::fromLatin1("2017-07-01T") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO zoned date") << QString::fromLatin1("2017-07-01Z") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO zoned empty time") << QString::fromLatin1("2017-07-01TZ") << Qt::ISODate << invalidDateTime(); // Test Qt::RFC2822Date format (RFC 2822). QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100") @@ -2387,8 +2396,8 @@ void tst_QDateTime::fromStringStringFormat_data() QTest::newRow("data14") << QString("32.01.2004") << QString("dd.MM.yyyy") << invalidDateTime(); QTest::newRow("data15") << QString("Thu January 2004") << QString("ddd MMMM yyyy") << QDateTime(QDate(2004, 1, 1), QTime()); QTest::newRow("data16") << QString("2005-06-28T07:57:30.001Z") - << QString("yyyy-MM-ddThh:mm:ss.zZ") - << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 1)); + << QString("yyyy-MM-ddThh:mm:ss.zt") + << QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 1), Qt::UTC); } void tst_QDateTime::fromStringStringFormat() @@ -2476,21 +2485,19 @@ void tst_QDateTime::fromStringToStringLocale() QLocale def; QLocale::setDefault(QLocale(QLocale::French, QLocale::France)); +#define ROUNDTRIP(format) \ + QCOMPARE(QDateTime::fromString(dateTime.toString(format), format), dateTime) - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::DefaultLocaleShortDate), Qt::DefaultLocaleShortDate), dateTime); - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::SystemLocaleShortDate), Qt::SystemLocaleShortDate), dateTime); + ROUNDTRIP(Qt::DefaultLocaleShortDate); + ROUNDTRIP(Qt::SystemLocaleShortDate); // obsolete - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::SystemLocaleDate), Qt::SystemLocaleDate), dateTime); - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::LocaleDate), Qt::LocaleDate), dateTime); - - QEXPECT_FAIL("data0", "This format is apparently failing because of a bug in the datetime parser. (QTBUG-22833)", Continue); - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::DefaultLocaleLongDate), Qt::DefaultLocaleLongDate), dateTime); -#ifndef Q_OS_WIN - QEXPECT_FAIL("data0", "This format is apparently failing because of a bug in the datetime parser. (QTBUG-22833)", Continue); -#endif - QCOMPARE(QDateTime::fromString(dateTime.toString(Qt::SystemLocaleLongDate), Qt::SystemLocaleLongDate), dateTime); + ROUNDTRIP(Qt::SystemLocaleDate); + ROUNDTRIP(Qt::LocaleDate); + ROUNDTRIP(Qt::DefaultLocaleLongDate); + ROUNDTRIP(Qt::SystemLocaleLongDate); +#undef ROUNDTRIP QLocale::setDefault(def); } @@ -2625,6 +2632,71 @@ void tst_QDateTime::toOffsetFromUtc() QCOMPARE(dt2.time(), QTime(0, 0, 0)); } +void tst_QDateTime::zoneAtTime_data() +{ + QTest::addColumn<QByteArray>("ianaID"); + QTest::addColumn<QDate>("date"); + QTest::addColumn<int>("offset"); +#define ADDROW(name, zone, date, offset) \ + QTest::newRow(name) << QByteArray(zone) << (date) << (offset) + + // Check DST handling around epoch: + { + QDate epoch(1970, 1, 1); + ADDROW("epoch:UTC", "UTC", epoch, 0); + // Paris and Berlin skipped DST around 1970; but Rome used it. + ADDROW("epoch:CET", "Europe/Rome", epoch, 3600); + ADDROW("epoch:PST", "America/Vancouver", epoch, -8 * 3600); + ADDROW("epoch:EST", "America/New_York", epoch, -5 * 3600); + } + { + // QDateTime deliberately ignores DST before the epoch. + QDate summer69(1969, 8, 15); // Woodstock started + ADDROW("summer69:UTC", "UTC", summer69, 0); + ADDROW("summer69:CET", "Europe/Rome", summer69, 3600); + ADDROW("summer69:PST", "America/Vancouver", summer69, -8 * 3600); + ADDROW("summer69:EST", "America/New_York", summer69, -5 * 3600); + } + { + // ... but takes it into account after: + QDate summer70(1970, 8, 26); // Isle of Wight festival + ADDROW("summer70:UTC", "UTC", summer70, 0); + ADDROW("summer70:CET", "Europe/Rome", summer70, 2 * 3600); + ADDROW("summer70:PST", "America/Vancouver", summer70, -7 * 3600); + ADDROW("summer70:EST", "America/New_York", summer70, -4 * 3600); + } + +#ifndef Q_OS_WIN + // Bracket a few noteworthy transitions: + ADDROW("before:ACWST", "Australia/Eucla", QDate(1974, 10, 26), 31500); // 8:45 + ADDROW("after:ACWST", "Australia/Eucla", QDate(1974, 10, 27), 35100); // 9:45 + ADDROW("before:NPT", "Asia/Kathmandu", QDate(1985, 12, 31), 19800); // 5:30 + ADDROW("after:NPT", "Asia/Kathmandu", QDate(1986, 1, 1), 20700); // 5:45 + // The two that have skipped a day (each): + ADDROW("before:LINT", "Pacific/Kiritimati", QDate(1994, 12, 31), -36000); + ADDROW("after:LINT", "Pacific/Kiritimati", QDate(1995, 2, 1), 14 * 3600); + ADDROW("after:WST", "Pacific/Apia", QDate(2011, 12, 31), 14 * 3600); +#endif // MS lacks ACWST, NPT; doesn't grok date-line crossings; and Windows 7 lacks LINT. + ADDROW("before:WST", "Pacific/Apia", QDate(2011, 12, 29), -36000); +#undef ADDROW +} + +void tst_QDateTime::zoneAtTime() +{ + QFETCH(QByteArray, ianaID); + QFETCH(QDate, date); + QFETCH(int, offset); + const QTime noon(12, 0); + + QTimeZone zone(ianaID); + QVERIFY(zone.isValid()); + QCOMPARE(QDateTime(date, noon, zone).offsetFromUtc(), offset); + if (date.year() < 1970) + QCOMPARE(zone.standardTimeOffset(QDateTime(date, noon, zone)), offset); + else // zone.offsetFromUtc *does* include DST, even before epoch + QCOMPARE(zone.offsetFromUtc(QDateTime(date, noon, zone)), offset); +} + void tst_QDateTime::timeZoneAbbreviation() { QDateTime dt1(QDate(2013, 1, 1), QTime(1, 0, 0), Qt::OffsetFromUTC, 60 * 60); diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 943b4316ff..0015efacfa 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -60,6 +60,7 @@ private slots: void compare2(); void iterators(); // sligthly modified from tst_QMap void keyIterator(); + void keyValueIterator(); void keys_values_uniqueKeys(); // slightly modified from tst_QMap void noNeedlessRehashes(); @@ -1124,6 +1125,60 @@ void tst_QHash::keyIterator() Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value); } +void tst_QHash::keyValueIterator() +{ + QHash<int, int> hash; + typedef QHash<int, int>::const_key_value_iterator::value_type entry_type; + + for (int i = 0; i < 100; ++i) + hash.insert(i, i * 100); + + auto key_value_it = hash.constKeyValueBegin(); + auto it = hash.cbegin(); + + + for (int i = 0; i < hash.size(); ++i) { + QVERIFY(key_value_it != hash.constKeyValueEnd()); + QVERIFY(it != hash.cend()); + + entry_type pair(it.key(), it.value()); + QCOMPARE(*key_value_it, pair); + ++key_value_it; + ++it; + } + + QVERIFY(key_value_it == hash.constKeyValueEnd()); + QVERIFY(it == hash.cend()); + + int key = 50; + int value = 50 * 100; + entry_type pair(key, value); + key_value_it = std::find(hash.constKeyValueBegin(), hash.constKeyValueEnd(), pair); + it = std::find(hash.cbegin(), hash.cend(), value); + + QVERIFY(key_value_it != hash.constKeyValueEnd()); + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + key = 99; + value = 99 * 100; + QCOMPARE(std::count(hash.constKeyValueBegin(), hash.constKeyValueEnd(), entry_type(key, value)), 1); +} + void tst_QHash::rehash_isnt_quadratic() { // this test should be incredibly slow if rehash() is quadratic diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index 4a81adf9fe..124e3cdf00 100644 --- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -49,6 +49,7 @@ public slots: void init(); private Q_SLOTS: + void consistent(); void qhash(); void qhash_of_empty_and_null_qstring(); void qhash_of_empty_and_null_qbytearray(); @@ -61,6 +62,17 @@ private Q_SLOTS: void setGlobalQHashSeed(); }; +void tst_QHashFunctions::consistent() +{ + // QString-like + { + const QString s = QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16); + + QCOMPARE(qHash(s), qHash(QStringRef(&s))); + QCOMPARE(qHash(s), qHash(QStringView(s))); + } +} + void tst_QHashFunctions::initTestCase() { Q_STATIC_ASSERT(int(RandomSeed) > 0); @@ -160,6 +172,14 @@ void tst_QHashFunctions::qhash_of_empty_and_null_qstring() QString null, empty(""); QCOMPARE(null, empty); QCOMPARE(qHash(null, seed), qHash(empty, seed)); + + QStringRef nullRef, emptyRef(&empty); + QCOMPARE(nullRef, emptyRef); + QCOMPARE(qHash(nullRef, seed), qHash(emptyRef, seed)); + + QStringView nullView, emptyView(empty); + QCOMPARE(nullView, emptyView); + QCOMPARE(qHash(nullView, seed), qHash(emptyView, seed)); } void tst_QHashFunctions::qhash_of_empty_and_null_qbytearray() @@ -264,17 +284,17 @@ void tst_QHashFunctions::rangeCommutative() void tst_QHashFunctions::setGlobalQHashSeed() { // Setter works as advertised - qSetGlobalQHashSeed(0x10101010); - QCOMPARE(qGlobalQHashSeed(), 0x10101010); + qSetGlobalQHashSeed(0); + QCOMPARE(qGlobalQHashSeed(), 0); // Creating a new QHash doesn't reset the seed QHash<QString, int> someHash; someHash.insert("foo", 42); - QCOMPARE(qGlobalQHashSeed(), 0x10101010); + QCOMPARE(qGlobalQHashSeed(), 0); // Reset works as advertised qSetGlobalQHashSeed(-1); - QVERIFY(qGlobalQHashSeed() != -1); + QVERIFY(qGlobalQHashSeed() > 0); } QTEST_APPLESS_MAIN(tst_QHashFunctions) diff --git a/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp b/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp index a68671d899..c8373b6ae9 100644 --- a/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp +++ b/tests/auto/corelib/tools/qlatin1string/tst_qlatin1string.cpp @@ -48,6 +48,7 @@ private Q_SLOTS: void midLeftRight(); void nullString(); void emptyString(); + void iterators(); void relationalOperators_data(); void relationalOperators(); }; @@ -155,6 +156,22 @@ void tst_QLatin1String::emptyString() } } +void tst_QLatin1String::iterators() +{ + QLatin1String hello("hello"); + QLatin1String olleh("olleh"); + + QVERIFY(std::equal(hello.begin(), hello.end(), + olleh.rbegin())); + QVERIFY(std::equal(hello.rbegin(), hello.rend(), + QT_MAKE_CHECKED_ARRAY_ITERATOR(olleh.begin(), olleh.size()))); + + QVERIFY(std::equal(hello.cbegin(), hello.cend(), + olleh.rbegin())); + QVERIFY(std::equal(hello.crbegin(), hello.crend(), + QT_MAKE_CHECKED_ARRAY_ITERATOR(olleh.begin(), olleh.size()))); +} + void tst_QLatin1String::relationalOperators_data() { QTest::addColumn<QLatin1StringContainer>("lhs"); diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 10d78b1f2f..d424e6086d 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -137,6 +137,8 @@ private slots: void textDirection_data(); void textDirection(); + void formattedDataSize_data(); + void formattedDataSize(); void bcp47Name(); private: @@ -1221,6 +1223,9 @@ void tst_QLocale::dayOfWeek() QCOMPARE(QLocale::c().toString(date, "ddd"), shortName); QCOMPARE(QLocale::c().toString(date, "dddd"), longName); + + QCOMPARE(QLocale::c().toString(date, QStringViewLiteral("ddd")), shortName); + QCOMPARE(QLocale::c().toString(date, QStringViewLiteral("dddd")), longName); } void tst_QLocale::formatDate_data() @@ -1263,6 +1268,7 @@ void tst_QLocale::formatDate() QLocale l(QLocale::C); QCOMPARE(l.toString(date, format), result); + QCOMPARE(l.toString(date, QStringView(format)), result); } @@ -1319,6 +1325,7 @@ void tst_QLocale::formatTime() QLocale l(QLocale::C); QCOMPARE(l.toString(time, format), result); + QCOMPARE(l.toString(time, QStringView(format)), result); } @@ -1480,6 +1487,7 @@ void tst_QLocale::formatDateTime() QLocale l(localeName); QCOMPARE(l.toString(dateTime, format), result); + QCOMPARE(l.toString(dateTime, QStringView(format)), result); } void tst_QLocale::formatTimeZone() @@ -2203,9 +2211,9 @@ void tst_QLocale::timeFormat() QCOMPARE(c.timeFormat(QLocale::NarrowFormat), c.timeFormat(QLocale::ShortFormat)); const QLocale no("no_NO"); - QCOMPARE(no.timeFormat(QLocale::NarrowFormat), QLatin1String("HH.mm")); - QCOMPARE(no.timeFormat(QLocale::ShortFormat), QLatin1String("HH.mm")); - QCOMPARE(no.timeFormat(QLocale::LongFormat), QLatin1String("HH.mm.ss t")); + QCOMPARE(no.timeFormat(QLocale::NarrowFormat), QLatin1String("HH:mm")); + QCOMPARE(no.timeFormat(QLocale::ShortFormat), QLatin1String("HH:mm")); + QCOMPARE(no.timeFormat(QLocale::LongFormat), QLatin1String("HH:mm:ss t")); const QLocale id("id_ID"); QCOMPARE(id.timeFormat(QLocale::ShortFormat), QLatin1String("HH.mm")); @@ -2227,9 +2235,9 @@ void tst_QLocale::dateTimeFormat() QCOMPARE(c.dateTimeFormat(QLocale::NarrowFormat), c.dateTimeFormat(QLocale::ShortFormat)); const QLocale no("no_NO"); - QCOMPARE(no.dateTimeFormat(QLocale::NarrowFormat), QLatin1String("dd.MM.yyyy HH.mm")); - QCOMPARE(no.dateTimeFormat(QLocale::ShortFormat), QLatin1String("dd.MM.yyyy HH.mm")); - QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), QLatin1String("dddd d. MMMM yyyy HH.mm.ss t")); + QCOMPARE(no.dateTimeFormat(QLocale::NarrowFormat), QLatin1String("dd.MM.yyyy HH:mm")); + QCOMPARE(no.dateTimeFormat(QLocale::ShortFormat), QLatin1String("dd.MM.yyyy HH:mm")); + QCOMPARE(no.dateTimeFormat(QLocale::LongFormat), QLatin1String("dddd d. MMMM yyyy HH:mm:ss t")); } void tst_QLocale::monthName() @@ -2510,8 +2518,8 @@ void tst_QLocale::textDirection_data() default: break; } - QString testName = QLocalePrivate::languageToCode(QLocale::Language(language)); - QTest::newRow(testName.toLatin1().constData()) << language << int(QLocale::AnyScript) << rightToLeft; + const QLatin1String testName = QLocalePrivate::languageToCode(QLocale::Language(language)); + QTest::newRow(qPrintable(testName)) << language << int(QLocale::AnyScript) << rightToLeft; } QTest::newRow("pa_Arab") << int(QLocale::Punjabi) << int(QLocale::ArabicScript) << true; QTest::newRow("uz_Arab") << int(QLocale::Uzbek) << int(QLocale::ArabicScript) << true; @@ -2527,6 +2535,81 @@ void tst_QLocale::textDirection() QCOMPARE(locale.textDirection() == Qt::RightToLeft, rightToLeft); } +void tst_QLocale::formattedDataSize_data() +{ + QTest::addColumn<QLocale::Language>("language"); + QTest::addColumn<int>("decimalPlaces"); + QTest::addColumn<QLocale::DataSizeFormats>("units"); + QTest::addColumn<int>("bytes"); + QTest::addColumn<QString>("output"); + + struct { + const char *name; + QLocale::Language lang; + const char *bytes; + const char abbrev; + const char sep; // decimal separator + } data[] = { + { "English", QLocale::English, "bytes", 'B', '.' }, + { "French", QLocale::French, "octets", 'o', ',' }, + { "C", QLocale::C, "bytes", 'B', '.' } + }; + + for (const auto row : data) { +#define ROWB(id, deci, num, text) \ + QTest::addRow("%s-%s", row.name, id) \ + << row.lang << deci << format \ + << num << (QString(text) + QChar(' ') + QString(row.bytes)) +#define ROWQ(id, deci, num, head, tail) \ + QTest::addRow("%s-%s", row.name, id) \ + << row.lang << deci << format \ + << num << (QString(head) + QChar(row.sep) + QString(tail) + QChar(row.abbrev)) + + // Metatype system fails to handle raw enum members as format; needs variable + { + const QLocale::DataSizeFormats format = QLocale::DataSizeIecFormat; + ROWB("IEC-0", 2, 0, "0"); + ROWB("IEC-10", 2, 10, "10"); + ROWQ("IEC-12Ki", 2, 12345, "12", "06 Ki"); + ROWQ("IEC-16Ki", 2, 16384, "16", "00 Ki"); + ROWQ("IEC-1235k", 2, 1234567, "1", "18 Mi"); + ROWQ("IEC-1374k", 2, 1374744, "1", "31 Mi"); + ROWQ("IEC-1234M", 2, 1234567890, "1", "15 Gi"); + } + { + const QLocale::DataSizeFormats format = QLocale::DataSizeTraditionalFormat; + ROWB("Trad-0", 2, 0, "0"); + ROWB("Trad-10", 2, 10, "10"); + ROWQ("Trad-12Ki", 2, 12345, "12", "06 k"); + ROWQ("Trad-16Ki", 2, 16384, "16", "00 k"); + ROWQ("Trad-1235k", 2, 1234567, "1", "18 M"); + ROWQ("Trad-1374k", 2, 1374744, "1", "31 M"); + ROWQ("Trad-1234M", 2, 1234567890, "1", "15 G"); + } + { + const QLocale::DataSizeFormats format = QLocale::DataSizeSIFormat; + ROWB("Decimal-0", 2, 0, "0"); + ROWB("Decimal-10", 2, 10, "10"); + ROWQ("Decimal-16Ki", 2, 16384, "16", "38 k"); + ROWQ("Decimal-1234k", 2, 1234567, "1", "23 M"); + ROWQ("Decimal-1374k", 2, 1374744, "1", "37 M"); + ROWQ("Decimal-1234M", 2, 1234567890, "1", "23 G"); + } +#undef ROWQ +#undef ROWB + } +} + +void tst_QLocale::formattedDataSize() +{ + QFETCH(QLocale::Language, language); + QFETCH(int, decimalPlaces); + QFETCH(QLocale::DataSizeFormats, units); + QFETCH(int, bytes); + QFETCH(QString, output); + QCOMPARE(QLocale(language).formattedDataSize(bytes, decimalPlaces, units), output); +} + void tst_QLocale::bcp47Name() { QCOMPARE(QLocale("C").bcp47Name(), QStringLiteral("en")); diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro new file mode 100644 index 0000000000..26b3a47472 --- /dev/null +++ b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qmacautoreleasepool +QT = core testlib +SOURCES = tst_qmacautoreleasepool.mm diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm new file mode 100644 index 0000000000..8f1069f419 --- /dev/null +++ b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <Foundation/Foundation.h> + +class tst_QMacAutoreleasePool : public QObject +{ + Q_OBJECT +private slots: + void noPool(); + void rootLevelPool(); + void stackAllocatedPool(); + void heapAllocatedPool(); +}; + +static id lastDeallocedObject = nil; + +@interface DeallocTracker : NSObject @end +@implementation DeallocTracker +-(void)dealloc +{ + lastDeallocedObject = self; + [super dealloc]; +} +@end + +void tst_QMacAutoreleasePool::noPool() +{ + // No pool, will not be released, but should not crash + + [[[DeallocTracker alloc] init] autorelease]; +} + +void tst_QMacAutoreleasePool::rootLevelPool() +{ + // The root level case, no NSAutoreleasePool since we're not in the main + // runloop, and objects autoreleased as part of main. + + NSObject *allocedObject = nil; + { + QMacAutoReleasePool qtPool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + QCOMPARE(lastDeallocedObject, allocedObject); +} + +void tst_QMacAutoreleasePool::stackAllocatedPool() +{ + // The normal case, other pools surrounding our pool, draining + // our pool before any other pool. + + NSObject *allocedObject = nil; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + { + QMacAutoReleasePool qtPool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + QCOMPARE(lastDeallocedObject, allocedObject); + [pool drain]; +} + +void tst_QMacAutoreleasePool::heapAllocatedPool() +{ + // The special case, a pool allocated on the heap, or as a member of a + // heap allocated object. This is not a supported use of QMacAutoReleasePool, + // and will result in warnings if the pool is prematurely drained. + + NSObject *allocedObject = nil; + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + QMacAutoReleasePool *qtPool = nullptr; + { + qtPool = new QMacAutoReleasePool; + allocedObject = [[[DeallocTracker alloc] init] autorelease]; + } + [pool drain]; + delete qtPool; + } + QCOMPARE(lastDeallocedObject, allocedObject); +} + +QTEST_APPLESS_MAIN(tst_QMacAutoreleasePool) + +#include "tst_qmacautoreleasepool.moc" diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index f42ffc0471..b39444e76f 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -61,6 +61,7 @@ private slots: void iterators(); void keyIterator(); + void keyValueIterator(); void keys_values_uniqueKeys(); void qmultimap_specific(); @@ -863,6 +864,59 @@ void tst_QMap::keyIterator() Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value); } +void tst_QMap::keyValueIterator() +{ + QMap<int, int> map; + typedef QMap<int, int>::const_key_value_iterator::value_type entry_type; + + for (int i = 0; i < 100; ++i) + map.insert(i, i * 100); + + auto key_value_it = map.constKeyValueBegin(); + auto it = map.cbegin(); + + for (int i = 0; i < map.size(); ++i) { + QVERIFY(key_value_it != map.constKeyValueEnd()); + QVERIFY(it != map.cend()); + + entry_type pair(it.key(), it.value()); + QCOMPARE(*key_value_it, pair); + ++key_value_it; + ++it; + } + + QVERIFY(key_value_it == map.constKeyValueEnd()); + QVERIFY(it == map.cend()); + + int key = 50; + int value = 50 * 100; + entry_type pair(key, value); + key_value_it = std::find(map.constKeyValueBegin(), map.constKeyValueEnd(), pair); + it = std::find(map.cbegin(), map.cend(), value); + + QVERIFY(key_value_it != map.constKeyValueEnd()); + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + ++it; + ++key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + + --it; + --key_value_it; + QCOMPARE(*key_value_it, entry_type(it.key(), it.value())); + key = 99; + value = 99 * 100; + QCOMPARE(std::count(map.constKeyValueBegin(), map.constKeyValueEnd(), entry_type(key, value)), 1); +} + void tst_QMap::keys_values_uniqueKeys() { QMap<QString, int> map; diff --git a/tests/auto/corelib/tools/qrect/tst_qrect.cpp b/tests/auto/corelib/tools/qrect/tst_qrect.cpp index d3c6412b0d..1c2221ec29 100644 --- a/tests/auto/corelib/tools/qrect/tst_qrect.cpp +++ b/tests/auto/corelib/tools/qrect/tst_qrect.cpp @@ -171,6 +171,7 @@ private slots: void containsPointF_data(); void containsPointF(); void smallRects() const; + void toRect(); }; // Used to work around some floating point precision problems. @@ -4331,5 +4332,36 @@ void tst_QRect::smallRects() const QVERIFY(r1 != r2); } +void tst_QRect::toRect() +{ + for (qreal x = 1.0; x < 2.0; x += 0.25) { + for (qreal y = 1.0; y < 2.0; y += 0.25) { + for (qreal w = 1.0; w < 2.0; w += 0.25) { + for (qreal h = 1.0; h < 2.0; h += 0.25) { + const QRectF rectf(x, y, w, h); + const QRectF rect = rectf.toRect(); + QVERIFY(qAbs(rect.x() - rectf.x()) < 1.0); + QVERIFY(qAbs(rect.y() - rectf.y()) < 1.0); + QVERIFY(qAbs(rect.width() - rectf.width()) < 1.0); + QVERIFY(qAbs(rect.height() - rectf.height()) < 1.0); + QVERIFY(qAbs(rect.right() - rectf.right()) < 1.0); + QVERIFY(qAbs(rect.bottom() - rectf.bottom()) < 1.0); + + const QRectF arect = rectf.toAlignedRect(); + QVERIFY(qAbs(arect.x() - rectf.x()) < 1.0); + QVERIFY(qAbs(arect.y() - rectf.y()) < 1.0); + QVERIFY(qAbs(arect.width() - rectf.width()) < 2.0); + QVERIFY(qAbs(arect.height() - rectf.height()) < 2.0); + QVERIFY(qAbs(arect.right() - rectf.right()) < 1.0); + QVERIFY(qAbs(arect.bottom() - rectf.bottom()) < 1.0); + + QVERIFY(arect.contains(rectf)); + QVERIFY(arect.contains(rect)); + } + } + } + } +} + QTEST_MAIN(tst_QRect) #include "tst_qrect.moc" diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp index 2a93250ba5..c828551e44 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp @@ -169,6 +169,7 @@ void consistencyCheck(const QRegularExpressionMatch &match) int length = match.capturedLength(i); QString captured = match.captured(i); QStringRef capturedRef = match.capturedRef(i); + QStringView capturedView = match.capturedView(i); if (!captured.isNull()) { QVERIFY(startPos >= 0); @@ -177,11 +178,13 @@ void consistencyCheck(const QRegularExpressionMatch &match) QVERIFY(endPos >= startPos); QVERIFY((endPos - startPos) == length); QVERIFY(captured == capturedRef); + QVERIFY(captured == capturedView); } else { QVERIFY(startPos == -1); QVERIFY(endPos == -1); QVERIFY((endPos - startPos) == length); QVERIFY(capturedRef.isNull()); + QVERIFY(capturedView.isNull()); } } } diff --git a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp index 21efaede00..a4b06d1b3b 100644 --- a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp +++ b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp @@ -88,7 +88,7 @@ class MySubClass : public MyClass void tst_QScopedPointer::useSubClassInConstructor() { /* Use a syntax which users typically would do. */ - QScopedPointer<MyClass> p(new MyClass()); + QScopedPointer<MyClass> p(new MySubClass()); } void tst_QScopedPointer::dataOnValue() diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 442d4d089c..e1dcdb8407 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -1884,7 +1884,7 @@ class StrongThread: public QThread protected: void run() { - usleep(rand() % 2000); + usleep(QRandomGenerator::global()->bounded(2000)); ptr->ref(); ptr.clear(); } @@ -1897,7 +1897,7 @@ class WeakThread: public QThread protected: void run() { - usleep(rand() % 2000); + usleep(QRandomGenerator::global()->bounded(2000)); QSharedPointer<ThreadData> ptr = weak; if (ptr) ptr->ref(); @@ -1959,7 +1959,6 @@ void tst_QSharedPointer::threadStressTest() base.clear(); - srand(time(NULL)); // start threads for (int i = 0; i < allThreads.count(); ++i) if (allThreads[i]) allThreads[i]->start(); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 24f16b9911..70ccc72630 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -4726,8 +4726,8 @@ void tst_QString::arg() QString s14( "%1%2%3" ); QCOMPARE( s4.arg("foo"), QLatin1String("[foo]") ); - QCOMPARE( s5.arg("foo"), QLatin1String("[foo]") ); - QCOMPARE( s6.arg("foo"), QLatin1String("[foo]") ); + QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") ); + QCOMPARE( s6.arg(QStringViewLiteral("foo")), QLatin1String("[foo]") ); QCOMPARE( s7.arg("foo"), QLatin1String("[foo]") ); QCOMPARE( s8.arg("foo"), QLatin1String("[foo %1]") ); QCOMPARE( s8.arg("foo").arg("bar"), QLatin1String("[foo bar]") ); @@ -4788,11 +4788,11 @@ void tst_QString::arg() QCOMPARE( QString("%%%1%%%2").arg("foo").arg("bar"), QLatin1String("%%foo%%bar") ); QCOMPARE( QString("%1").arg("hello", -10), QLatin1String("hello ") ); - QCOMPARE( QString("%1").arg("hello", -5), QLatin1String("hello") ); - QCOMPARE( QString("%1").arg("hello", -2), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(QLatin1String("hello"), -5), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), -2), QLatin1String("hello") ); QCOMPARE( QString("%1").arg("hello", 0), QLatin1String("hello") ); - QCOMPARE( QString("%1").arg("hello", 2), QLatin1String("hello") ); - QCOMPARE( QString("%1").arg("hello", 5), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(QLatin1String("hello"), 2), QLatin1String("hello") ); + QCOMPARE( QString("%1").arg(QStringViewLiteral("hello"), 5), QLatin1String("hello") ); QCOMPARE( QString("%1").arg("hello", 10), QLatin1String(" hello") ); QCOMPARE( QString("%1%1").arg("hello"), QLatin1String("hellohello") ); QCOMPARE( QString("%2%1").arg("hello"), QLatin1String("%2hello") ); @@ -6067,14 +6067,6 @@ void tst_QString::compare_data() lower += QChar(QChar::lowSurrogate(0x10428)); QTest::newRow("data8") << upper << lower << -1 << 0; - QTest::newRow("vectorized-boundaries-7") << QString("1234567") << QString("abcdefg") << -1 << -1; - QTest::newRow("vectorized-boundaries-8") << QString("12345678") << QString("abcdefgh") << -1 << -1; - QTest::newRow("vectorized-boundaries-9") << QString("123456789") << QString("abcdefghi") << -1 << -1; - - QTest::newRow("vectorized-boundaries-15") << QString("123456789012345") << QString("abcdefghiklmnop") << -1 << -1; - QTest::newRow("vectorized-boundaries-16") << QString("1234567890123456") << QString("abcdefghiklmnopq") << -1 << -1; - QTest::newRow("vectorized-boundaries-17") << QString("12345678901234567") << QString("abcdefghiklmnopqr") << -1 << -1; - // embedded nulls // These don't work as of now. It's OK that these don't work since \0 is not a valid unicode /*QTest::newRow("data10") << QString(QByteArray("\0", 1)) << QString(QByteArray("\0", 1)) << 0 << 0; @@ -6083,6 +6075,44 @@ void tst_QString::compare_data() QTest::newRow("data13") << QString("ab\0c") << QString(QByteArray("ab\0c", 4)) << 0 << 0; QTest::newRow("data14") << QString(QByteArray("ab\0c", 4)) << QString("abc") << -1 << -1; QTest::newRow("data15") << QString("abc") << QString(QByteArray("ab\0c", 4)) << 1 << 1;*/ + + // All tests below (generated by the 3 for-loops) are meant to excercise the vectorized versions + // of ucstrncmp. + + QString in1, in2; + for (int i = 0; i < 70; ++i) { + in1 += QString::number(i % 10); + in2 += QString::number((70 - i + 1) % 10); + } + Q_ASSERT(in1.length() == in2.length()); + Q_ASSERT(in1 != in2); + Q_ASSERT(in1.at(0) < in2.at(0)); + for (int i = 0; i < in1.length(); ++i) { + Q_ASSERT(in1.at(i) != in2.at(i)); + } + + for (int i = 1; i <= 65; ++i) { + QString inp1 = in1.left(i); + QString inp2 = in2.left(i); + QTest::addRow("all-different-%d", i) << inp1 << inp2 << -1 << -1; + } + + for (int i = 1; i <= 65; ++i) { + QString start(i - 1, 'a'); + + QString in = start + QLatin1Char('a'); + QTest::addRow("all-same-%d", i) << in << in << 0 << 0; + + QString in2 = start + QLatin1Char('b'); + QTest::addRow("last-different-%d", i) << in << in2 << -1 << -1; + } + + for (int i = 0; i < 16; ++i) { + QString in1(16, 'a'); + QString in2 = in1; + in2[i] = 'b'; + QTest::addRow("all-same-except-char-%d", i) << in1 << in2 << -1 << -1; + } } static bool isLatin(const QString &s) diff --git a/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro b/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro index bc38b17949..a4e91e38bd 100644 --- a/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro +++ b/tests/auto/corelib/tools/qstringapisymmetry/qstringapisymmetry.pro @@ -3,3 +3,4 @@ TARGET = tst_qstringapisymmetry QT = core testlib SOURCES = tst_qstringapisymmetry.cpp qtConfig(c++14): CONFIG += c++14 +qtConfig(c++1z): CONFIG += c++1z diff --git a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp index 9d9b47b61e..61d1f86f00 100644 --- a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp +++ b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp @@ -31,6 +31,7 @@ #undef QT_ASCII_CAST_WARNINGS #include <QString> +#include <QStringView> #include <QChar> #include <QStringRef> #include <QLatin1String> @@ -44,6 +45,7 @@ Q_DECLARE_METATYPE(QStringRef) template <typename T> QString toQString(const T &t) { return QString(t); } QString toQString(const QStringRef &ref) { return ref.toString(); } +QString toQString(QStringView view) { return view.toString(); } // FIXME: these are missing at the time of writing, add them, then remove the dummies here: #define MAKE_RELOP(op, A1, A2) \ @@ -81,13 +83,15 @@ class tst_QStringApiSymmetry : public QObject void compare_impl() const; private Q_SLOTS: - // test all combinations of {QChar, QStringRef, QString, QLatin1String, QByteArray, const char*} + // test all combinations of {QChar, QStringRef, QString, QStringView, QLatin1String, QByteArray, const char*} void compare_QChar_QChar_data() { compare_data(false); } void compare_QChar_QChar() { compare_impl<QChar, QChar>(); } void compare_QChar_QStringRef_data() { compare_data(false); } void compare_QChar_QStringRef() { compare_impl<QChar, QStringRef>(); } void compare_QChar_QString_data() { compare_data(false); } void compare_QChar_QString() { compare_impl<QChar, QString>(); } + void compare_QChar_QStringView_data() { compare_data(false); } + void compare_QChar_QStringView() { compare_impl<QChar, QStringView>(); } void compare_QChar_QLatin1String_data() { compare_data(false); } void compare_QChar_QLatin1String() { compare_impl<QChar, QLatin1String>(); } void compare_QChar_QByteArray_data() { compare_data(false); } @@ -101,6 +105,8 @@ private Q_SLOTS: void compare_QStringRef_QStringRef() { compare_impl<QStringRef, QStringRef>(); } void compare_QStringRef_QString_data() { compare_data(); } void compare_QStringRef_QString() { compare_impl<QStringRef, QString>(); } + void compare_QStringRef_QStringView_data() { compare_data(); } + void compare_QStringRef_QStringView() { compare_impl<QStringRef, QStringView>(); } void compare_QStringRef_QLatin1String_data() { compare_data(); } void compare_QStringRef_QLatin1String() { compare_impl<QStringRef, QLatin1String>(); } void compare_QStringRef_QByteArray_data() { compare_data(); } @@ -114,6 +120,8 @@ private Q_SLOTS: void compare_QString_QStringRef() { compare_impl<QString, QStringRef>(); } void compare_QString_QString_data() { compare_data(); } void compare_QString_QString() { compare_impl<QString, QString>(); } + void compare_QString_QStringView_data() { compare_data(); } + void compare_QString_QStringView() { compare_impl<QString, QStringView>(); } void compare_QString_QLatin1String_data() { compare_data(); } void compare_QString_QLatin1String() { compare_impl<QString, QLatin1String>(); } void compare_QString_QByteArray_data() { compare_data(); } @@ -121,12 +129,25 @@ private Q_SLOTS: void compare_QString_const_char_star_data() { compare_data(); } void compare_QString_const_char_star() { compare_impl<QString, const char *>(); } + void compare_QStringView_QChar_data() { compare_data(false); } + void compare_QStringView_QChar() { compare_impl<QStringView, QChar>(); } + void compare_QStringView_QStringRef_data() { compare_data(); } + void compare_QStringView_QStringRef() { compare_impl<QStringView, QStringRef>(); } + void compare_QStringView_QString_data() { compare_data(); } + void compare_QStringView_QString() { compare_impl<QStringView, QString>(); } + void compare_QStringView_QStringView_data() { compare_data(); } + void compare_QStringView_QStringView() { compare_impl<QStringView, QStringView>(); } + void compare_QStringView_QLatin1String_data() { compare_data(); } + void compare_QStringView_QLatin1String() { compare_impl<QStringView, QLatin1String>(); } + void compare_QLatin1String_QChar_data() { compare_data(false); } void compare_QLatin1String_QChar() { compare_impl<QLatin1String, QChar>(); } void compare_QLatin1String_QStringRef_data() { compare_data(); } void compare_QLatin1String_QStringRef() { compare_impl<QLatin1String, QStringRef>(); } void compare_QLatin1String_QString_data() { compare_data(); } void compare_QLatin1String_QString() { compare_impl<QLatin1String, QString>(); } + void compare_QLatin1String_QStringView_data() { compare_data(); } + void compare_QLatin1String_QStringView() { compare_impl<QLatin1String, QStringView>(); } void compare_QLatin1String_QLatin1String_data() { compare_data(); } void compare_QLatin1String_QLatin1String() { compare_impl<QLatin1String, QLatin1String>(); } void compare_QLatin1String_QByteArray_data() { compare_data(); } @@ -160,6 +181,181 @@ private Q_SLOTS: //void compare_const_char_star_const_char_star_data() { compare_data(); } //void compare_const_char_star_const_char_star() { compare_impl<const char *, const char *>(); } +private: + void startsWith_data(bool rhsIsQChar = false); + template <typename Haystack, typename Needle> void startsWith_impl() const; + + void endsWith_data(bool rhsIsQChar = false); + template <typename Haystack, typename Needle> void endsWith_impl() const; + +private Q_SLOTS: + // test all combinations of {QString, QStringRef, QStringView, QLatin1String} x {QString, QStringRef, QStringView, QLatin1String, QChar}: + void startsWith_QString_QString_data() { startsWith_data(); } + void startsWith_QString_QString() { startsWith_impl<QString, QString>(); } + void startsWith_QString_QStringRef_data() { startsWith_data(); } + void startsWith_QString_QStringRef() { startsWith_impl<QString, QStringRef>(); } + void startsWith_QString_QStringView_data() { startsWith_data(); } + void startsWith_QString_QStringView() { startsWith_impl<QString, QStringView>(); } + void startsWith_QString_QLatin1String_data() { startsWith_data(); } + void startsWith_QString_QLatin1String() { startsWith_impl<QString, QLatin1String>(); } + void startsWith_QString_QChar_data() { startsWith_data(false); } + void startsWith_QString_QChar() { startsWith_impl<QString, QChar>(); } + + void startsWith_QStringRef_QString_data() { startsWith_data(); } + void startsWith_QStringRef_QString() { startsWith_impl<QStringRef, QString>(); } + void startsWith_QStringRef_QStringRef_data() { startsWith_data(); } + void startsWith_QStringRef_QStringRef() { startsWith_impl<QStringRef, QStringRef>(); } + void startsWith_QStringRef_QStringView_data() { startsWith_data(); } + void startsWith_QStringRef_QStringView() { startsWith_impl<QStringRef, QStringView>(); } + void startsWith_QStringRef_QLatin1String_data() { startsWith_data(); } + void startsWith_QStringRef_QLatin1String() { startsWith_impl<QStringRef, QLatin1String>(); } + void startsWith_QStringRef_QChar_data() { startsWith_data(false); } + void startsWith_QStringRef_QChar() { startsWith_impl<QStringRef, QChar>(); } + + void startsWith_QStringView_QString_data() { startsWith_data(); } + void startsWith_QStringView_QString() { startsWith_impl<QStringView, QString>(); } + void startsWith_QStringView_QStringRef_data() { startsWith_data(); } + void startsWith_QStringView_QStringRef() { startsWith_impl<QStringView, QStringRef>(); } + void startsWith_QStringView_QStringView_data() { startsWith_data(); } + void startsWith_QStringView_QStringView() { startsWith_impl<QStringView, QStringView>(); } + void startsWith_QStringView_QLatin1String_data() { startsWith_data(); } + void startsWith_QStringView_QLatin1String() { startsWith_impl<QStringView, QLatin1String>(); } + void startsWith_QStringView_QChar_data() { startsWith_data(false); } + void startsWith_QStringView_QChar() { startsWith_impl<QStringView, QChar>(); } + + void startsWith_QLatin1String_QString_data() { startsWith_data(); } + void startsWith_QLatin1String_QString() { startsWith_impl<QLatin1String, QString>(); } + void startsWith_QLatin1String_QStringRef_data() { startsWith_data(); } + void startsWith_QLatin1String_QStringRef() { startsWith_impl<QLatin1String, QStringRef>(); } + void startsWith_QLatin1String_QStringView_data() { startsWith_data(); } + void startsWith_QLatin1String_QStringView() { startsWith_impl<QLatin1String, QStringView>(); } + void startsWith_QLatin1String_QLatin1String_data() { startsWith_data(); } + void startsWith_QLatin1String_QLatin1String() { startsWith_impl<QLatin1String, QLatin1String>(); } + void startsWith_QLatin1String_QChar_data() { startsWith_data(false); } + void startsWith_QLatin1String_QChar() { startsWith_impl<QLatin1String, QChar>(); } + + void endsWith_QString_QString_data() { endsWith_data(); } + void endsWith_QString_QString() { endsWith_impl<QString, QString>(); } + void endsWith_QString_QStringRef_data() { endsWith_data(); } + void endsWith_QString_QStringRef() { endsWith_impl<QString, QStringRef>(); } + void endsWith_QString_QStringView_data() { endsWith_data(); } + void endsWith_QString_QStringView() { endsWith_impl<QString, QStringView>(); } + void endsWith_QString_QLatin1String_data() { endsWith_data(); } + void endsWith_QString_QLatin1String() { endsWith_impl<QString, QLatin1String>(); } + void endsWith_QString_QChar_data() { endsWith_data(false); } + void endsWith_QString_QChar() { endsWith_impl<QString, QChar>(); } + + void endsWith_QStringRef_QString_data() { endsWith_data(); } + void endsWith_QStringRef_QString() { endsWith_impl<QStringRef, QString>(); } + void endsWith_QStringRef_QStringRef_data() { endsWith_data(); } + void endsWith_QStringRef_QStringRef() { endsWith_impl<QStringRef, QStringRef>(); } + void endsWith_QStringRef_QStringView_data() { endsWith_data(); } + void endsWith_QStringRef_QStringView() { endsWith_impl<QStringRef, QStringView>(); } + void endsWith_QStringRef_QLatin1String_data() { endsWith_data(); } + void endsWith_QStringRef_QLatin1String() { endsWith_impl<QStringRef, QLatin1String>(); } + void endsWith_QStringRef_QChar_data() { endsWith_data(false); } + void endsWith_QStringRef_QChar() { endsWith_impl<QStringRef, QChar>(); } + + void endsWith_QStringView_QString_data() { endsWith_data(); } + void endsWith_QStringView_QString() { endsWith_impl<QStringView, QString>(); } + void endsWith_QStringView_QStringRef_data() { endsWith_data(); } + void endsWith_QStringView_QStringRef() { endsWith_impl<QStringView, QStringRef>(); } + void endsWith_QStringView_QStringView_data() { endsWith_data(); } + void endsWith_QStringView_QStringView() { endsWith_impl<QStringView, QStringView>(); } + void endsWith_QStringView_QLatin1String_data() { endsWith_data(); } + void endsWith_QStringView_QLatin1String() { endsWith_impl<QStringView, QLatin1String>(); } + void endsWith_QStringView_QChar_data() { endsWith_data(false); } + void endsWith_QStringView_QChar() { endsWith_impl<QStringView, QChar>(); } + + void endsWith_QLatin1String_QString_data() { endsWith_data(); } + void endsWith_QLatin1String_QString() { endsWith_impl<QLatin1String, QString>(); } + void endsWith_QLatin1String_QStringRef_data() { endsWith_data(); } + void endsWith_QLatin1String_QStringRef() { endsWith_impl<QLatin1String, QStringRef>(); } + void endsWith_QLatin1String_QStringView_data() { endsWith_data(); } + void endsWith_QLatin1String_QStringView() { endsWith_impl<QLatin1String, QStringView>(); } + void endsWith_QLatin1String_QLatin1String_data() { endsWith_data(); } + void endsWith_QLatin1String_QLatin1String() { endsWith_impl<QLatin1String, QLatin1String>(); } + void endsWith_QLatin1String_QChar_data() { endsWith_data(false); } + void endsWith_QLatin1String_QChar() { endsWith_impl<QLatin1String, QChar>(); } + +private: + void mid_data(); + template <typename String> void mid_impl(); + + void left_data(); + template <typename String> void left_impl(); + + void right_data(); + template <typename String> void right_impl(); + + void chop_data(); + template <typename String> void chop_impl(); + + void truncate_data() { left_data(); } + template <typename String> void truncate_impl(); + +private Q_SLOTS: + + void mid_QString_data() { mid_data(); } + void mid_QString() { mid_impl<QString>(); } + void mid_QStringRef_data() { mid_data(); } + void mid_QStringRef() { mid_impl<QStringRef>(); } + void mid_QStringView_data() { mid_data(); } + void mid_QStringView() { mid_impl<QStringView>(); } + void mid_QLatin1String_data() { mid_data(); } + void mid_QLatin1String() { mid_impl<QLatin1String>(); } + void mid_QByteArray_data() { mid_data(); } + void mid_QByteArray() { mid_impl<QByteArray>(); } + + void left_truncate_QString_data() { left_data(); } + void left_truncate_QString() { left_impl<QString>(); } + void left_truncate_QStringRef_data() { left_data(); } + void left_truncate_QStringRef() { left_impl<QStringRef>(); } + void left_truncate_QStringView_data() { left_data(); } + void left_truncate_QStringView() { left_impl<QStringView>(); } + void left_truncate_QLatin1String_data() { left_data(); } + void left_truncate_QLatin1String() { left_impl<QLatin1String>(); } + void left_truncate_QByteArray_data() { left_data(); } + void left_truncate_QByteArray() { left_impl<QByteArray>(); } + + void right_QString_data() { right_data(); } + void right_QString() { right_impl<QString>(); } + void right_QStringRef_data() { right_data(); } + void right_QStringRef() { right_impl<QStringRef>(); } + void right_QStringView_data() { right_data(); } + void right_QStringView() { right_impl<QStringView>(); } + void right_QLatin1String_data() { right_data(); } + void right_QLatin1String() { right_impl<QLatin1String>(); } + void right_QByteArray_data() { right_data(); } + void right_QByteArray() { right_impl<QByteArray>(); } + + void chop_QString_data() { chop_data(); } + void chop_QString() { chop_impl<QString>(); } + void chop_QStringRef_data() { chop_data(); } + void chop_QStringRef() { chop_impl<QStringRef>(); } + void chop_QStringView_data() { chop_data(); } + void chop_QStringView() { chop_impl<QStringView>(); } + void chop_QLatin1String_data() { chop_data(); } + void chop_QLatin1String() { chop_impl<QLatin1String>(); } + void chop_QByteArray_data() { chop_data(); } + void chop_QByteArray() { chop_impl<QByteArray>(); } + +private: + void trimmed_data(); + template <typename String> void trimmed_impl(); + +private Q_SLOTS: + void trim_trimmed_QString_data() { trimmed_data(); } + void trim_trimmed_QString() { trimmed_impl<QString>(); } + void trim_trimmed_QStringRef_data() { trimmed_data(); } + void trim_trimmed_QStringRef() { trimmed_impl<QStringRef>(); } + void trim_trimmed_QStringView_data() { trimmed_data(); } + void trim_trimmed_QStringView() { trimmed_impl<QStringView>(); } + void trim_trimmed_QLatin1String_data() { trimmed_data(); } + void trim_trimmed_QLatin1String() { trimmed_impl<QLatin1String>(); } + void trim_trimmed_QByteArray_data() { trimmed_data(); } + void trim_trimmed_QByteArray() { trimmed_impl<QByteArray>(); } + // // UTF-16-only checks: // @@ -183,21 +379,29 @@ private Q_SLOTS: void toLocal8Bit_QString() { toLocal8Bit_impl<QString>(); } void toLocal8Bit_QStringRef_data() { toLocal8Bit_data(); } void toLocal8Bit_QStringRef() { toLocal8Bit_impl<QStringRef>(); } + void toLocal8Bit_QStringView_data() { toLocal8Bit_data(); } + void toLocal8Bit_QStringView() { toLocal8Bit_impl<QStringView>(); } void toLatin1_QString_data() { toLatin1_data(); } void toLatin1_QString() { toLatin1_impl<QString>(); } void toLatin1_QStringRef_data() { toLatin1_data(); } void toLatin1_QStringRef() { toLatin1_impl<QStringRef>(); } + void toLatin1_QStringView_data() { toLatin1_data(); } + void toLatin1_QStringView() { toLatin1_impl<QStringView>(); } void toUtf8_QString_data() { toUtf8_data(); } void toUtf8_QString() { toUtf8_impl<QString>(); } void toUtf8_QStringRef_data() { toUtf8_data(); } void toUtf8_QStringRef() { toUtf8_impl<QStringRef>(); } + void toUtf8_QStringView_data() { toUtf8_data(); } + void toUtf8_QStringView() { toUtf8_impl<QStringView>(); } void toUcs4_QString_data() { toUcs4_data(); } void toUcs4_QString() { toUcs4_impl<QString>(); } void toUcs4_QStringRef_data() { toUcs4_data(); } void toUcs4_QStringRef() { toUcs4_impl<QStringRef>(); } + void toUcs4_QStringView_data() { toUcs4_data(); } + void toUcs4_QStringView() { toUcs4_impl<QStringView>(); } }; void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty) @@ -217,6 +421,9 @@ void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty) QTest::newRow("null <> empty") << QStringRef() << QLatin1String() << QStringRef(&empty) << QLatin1String("") << 0 << 0; + QTest::newRow("empty <> null") << QStringRef(&empty) << QLatin1String("") + << QStringRef() << QLatin1String() + << 0 << 0; } #define ROW(lhs, rhs) \ @@ -239,10 +446,20 @@ void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty) #undef ROW } +template <typename String> String detached(String s) +{ + if (!s.isNull()) { // detaching loses nullness, but we need to preserve it + auto d = s.data(); + Q_UNUSED(d); + } + return s; +} + template <class Str> Str make(const QStringRef &sf, QLatin1String l1, const QByteArray &u8); template <> QChar make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf.isEmpty() ? QChar() : sf.at(0); } template <> QStringRef make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf; } template <> QString make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf.toString(); } +template <> QStringView make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf; } template <> QLatin1String make(const QStringRef &, QLatin1String l1, const QByteArray &) { return l1; } template <> QByteArray make(const QStringRef &, QLatin1String, const QByteArray &u8) { return u8; } template <> const char * make(const QStringRef &, QLatin1String, const QByteArray &u8) { return u8.data(); } @@ -260,6 +477,12 @@ struct has_nothrow_compare { }; template <typename LHS, typename RHS> +struct has_qCompareStrings { + enum { value = !std::is_same<LHS, QChar>::value && !std::is_same<RHS, QChar>::value && + !is_utf8_encoded<LHS>::value && !is_utf8_encoded<RHS>::value }; +}; + +template <typename LHS, typename RHS> void tst_QStringApiSymmetry::compare_impl() const { QFETCH(QStringRef, lhsUnicode); @@ -267,6 +490,8 @@ void tst_QStringApiSymmetry::compare_impl() const QFETCH(QStringRef, rhsUnicode); QFETCH(QLatin1String, rhsLatin1); QFETCH(int, caseSensitiveCompareResult); + QFETCH(const int, caseInsensitiveCompareResult); + Q_UNUSED(caseInsensitiveCompareResult); const auto lhsU8 = lhsUnicode.toUtf8(); const auto rhsU8 = rhsUnicode.toUtf8(); @@ -300,6 +525,529 @@ void tst_QStringApiSymmetry::compare_impl() const #undef CHECK } +static QString empty = QLatin1String(""); +// the tests below rely on the fact that these objects' names match their contents: +static QString a = QStringLiteral("a"); +static QString A = QStringLiteral("A"); +static QString b = QStringLiteral("b"); +static QString B = QStringLiteral("B"); +static QString c = QStringLiteral("c"); +static QString C = QStringLiteral("C"); +static QString ab = QStringLiteral("ab"); +static QString aB = QStringLiteral("aB"); +static QString Ab = QStringLiteral("Ab"); +static QString AB = QStringLiteral("AB"); +static QString bc = QStringLiteral("bc"); +static QString bC = QStringLiteral("bC"); +static QString Bc = QStringLiteral("Bc"); +static QString BC = QStringLiteral("BC"); +static QString abc = QStringLiteral("abc"); +static QString abC = QStringLiteral("abC"); +static QString aBc = QStringLiteral("aBc"); +static QString aBC = QStringLiteral("aBC"); +static QString Abc = QStringLiteral("Abc"); +static QString AbC = QStringLiteral("AbC"); +static QString ABc = QStringLiteral("ABc"); +static QString ABC = QStringLiteral("ABC"); + +void tst_QStringApiSymmetry::startsWith_data(bool rhsHasVariableLength) +{ + QTest::addColumn<QStringRef>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QStringRef>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<bool>("resultCS"); + QTest::addColumn<bool>("resultCIS"); + + if (rhsHasVariableLength) { + QTest::addRow("null ~= ^null") << QStringRef() << QLatin1String() + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("empty ~= ^null") << QStringRef(&empty) << QLatin1String("") + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("a ~= ^null") << QStringRef(&a) << QLatin1String("a") + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("null ~= ^empty") << QStringRef() << QLatin1String() + << QStringRef(&empty) << QLatin1String("") << false << false; + QTest::addRow("a ~= ^empty") << QStringRef(&a) << QLatin1String("a") + << QStringRef(&empty) << QLatin1String("") << true << true; + QTest::addRow("empty ~= ^empty") << QStringRef(&empty) << QLatin1String("") + << QStringRef(&empty) << QLatin1String("") << true << true; + } + QTest::addRow("null ~= ^a") << QStringRef() << QLatin1String() + << QStringRef(&a) << QLatin1String("a") << false << false; + QTest::addRow("empty ~= ^a") << QStringRef(&empty) << QLatin1String("") + << QStringRef(&a) << QLatin1String("a") << false << false; + +#define ROW(h, n, cs, cis) \ + QTest::addRow("%s ~= ^%s", #h, #n) << QStringRef(&h) << QLatin1String(#h) \ + << QStringRef(&n) << QLatin1String(#n) \ + << bool(cs) << bool(cis) + ROW(a, a, 1, 1); + ROW(a, A, 0, 1); + ROW(a, b, 0, 0); + + if (rhsHasVariableLength) + ROW(a, aB, 0, 0); + + ROW(ab, a, 1, 1); + if (rhsHasVariableLength) { + ROW(ab, ab, 1, 1); + ROW(ab, aB, 0, 1); + ROW(ab, Ab, 0, 1); + } + ROW(ab, c, 0, 0); + + if (rhsHasVariableLength) + ROW(ab, abc, 0, 0); + + ROW(Abc, c, 0, 0); + if (rhsHasVariableLength) { + ROW(Abc, ab, 0, 1); + ROW(Abc, aB, 0, 1); + ROW(Abc, Ab, 1, 1); + ROW(Abc, AB, 0, 1); + ROW(aBC, ab, 0, 1); + ROW(aBC, aB, 1, 1); + ROW(aBC, Ab, 0, 1); + ROW(aBC, AB, 0, 1); + } + ROW(ABC, b, 0, 0); + ROW(ABC, a, 0, 1); +#undef ROW +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::startsWith_impl() const +{ + QFETCH(const QStringRef, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QStringRef, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const bool, resultCS); + QFETCH(const bool, resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(haystackU16, haystackL1, haystackU8); + const auto needle = make<Needle>(needleU16, needleL1, needleU8); + + QCOMPARE(haystack.startsWith(needle), resultCS); + QCOMPARE(haystack.startsWith(needle, Qt::CaseSensitive), resultCS); + QCOMPARE(haystack.startsWith(needle, Qt::CaseInsensitive), resultCIS); +} + +void tst_QStringApiSymmetry::endsWith_data(bool rhsHasVariableLength) +{ + QTest::addColumn<QStringRef>("haystackU16"); + QTest::addColumn<QLatin1String>("haystackL1"); + QTest::addColumn<QStringRef>("needleU16"); + QTest::addColumn<QLatin1String>("needleL1"); + QTest::addColumn<bool>("resultCS"); + QTest::addColumn<bool>("resultCIS"); + + if (rhsHasVariableLength) { + QTest::addRow("null ~= null$") << QStringRef() << QLatin1String() + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("empty ~= null$") << QStringRef(&empty) << QLatin1String("") + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("a ~= null$") << QStringRef(&a) << QLatin1String("a") + << QStringRef() << QLatin1String() << true << true; + QTest::addRow("null ~= empty$") << QStringRef() << QLatin1String() + << QStringRef(&empty) << QLatin1String("") << false << false; + QTest::addRow("a ~= empty$") << QStringRef(&a) << QLatin1String("a") + << QStringRef(&empty) << QLatin1String("") << true << true; + QTest::addRow("empty ~= empty$") << QStringRef(&empty) << QLatin1String("") + << QStringRef(&empty) << QLatin1String("") << true << true; + } + QTest::addRow("null ~= a$") << QStringRef() << QLatin1String() + << QStringRef(&a) << QLatin1String("a") << false << false; + QTest::addRow("empty ~= a$") << QStringRef(&empty) << QLatin1String("") + << QStringRef(&a) << QLatin1String("a") << false << false; + +#define ROW(h, n, cs, cis) \ + QTest::addRow("%s ~= %s$", #h, #n) << QStringRef(&h) << QLatin1String(#h) \ + << QStringRef(&n) << QLatin1String(#n) \ + << bool(cs) << bool(cis) + ROW(a, a, 1, 1); + ROW(a, A, 0, 1); + ROW(a, b, 0, 0); + + if (rhsHasVariableLength) + ROW(b, ab, 0, 0); + + ROW(ab, b, 1, 1); + if (rhsHasVariableLength) { + ROW(ab, ab, 1, 1); + ROW(ab, aB, 0, 1); + ROW(ab, Ab, 0, 1); + } + ROW(ab, c, 0, 0); + + if (rhsHasVariableLength) + ROW(bc, abc, 0, 0); + + ROW(Abc, c, 1, 1); + if (rhsHasVariableLength) { + ROW(Abc, bc, 1, 1); + ROW(Abc, bC, 0, 1); + ROW(Abc, Bc, 0, 1); + ROW(Abc, BC, 0, 1); + ROW(aBC, bc, 0, 1); + ROW(aBC, bC, 0, 1); + ROW(aBC, Bc, 0, 1); + ROW(aBC, BC, 1, 1); + } + ROW(ABC, b, 0, 0); + ROW(ABC, a, 0, 0); +#undef ROW +} + +template <typename Haystack, typename Needle> +void tst_QStringApiSymmetry::endsWith_impl() const +{ + QFETCH(const QStringRef, haystackU16); + QFETCH(const QLatin1String, haystackL1); + QFETCH(const QStringRef, needleU16); + QFETCH(const QLatin1String, needleL1); + QFETCH(const bool, resultCS); + QFETCH(const bool, resultCIS); + + const auto haystackU8 = haystackU16.toUtf8(); + const auto needleU8 = needleU16.toUtf8(); + + const auto haystack = make<Haystack>(haystackU16, haystackL1, haystackU8); + const auto needle = make<Needle>(needleU16, needleL1, needleU8); + + QCOMPARE(haystack.endsWith(needle), resultCS); + QCOMPARE(haystack.endsWith(needle, Qt::CaseSensitive), resultCS); + QCOMPARE(haystack.endsWith(needle, Qt::CaseInsensitive), resultCIS); +} + +void tst_QStringApiSymmetry::mid_data() +{ + QTest::addColumn<QStringRef>("unicode"); + QTest::addColumn<QLatin1String>("latin1"); + QTest::addColumn<int>("pos"); + QTest::addColumn<int>("n"); + QTest::addColumn<QStringRef>("result"); + QTest::addColumn<QStringRef>("result2"); + + QTest::addRow("null") << QStringRef() << QLatin1String() << 0 << 0 << QStringRef() << QStringRef(); + QTest::addRow("empty") << QStringRef(&empty) << QLatin1String("") << 0 << 0 << QStringRef(&empty) << QStringRef(&empty); + + // Some classes' mid() implementations have a wide contract, others a narrow one + // so only test valid arguents here: +#define ROW(base, p, n, r1, r2) \ + QTest::addRow("%s%d%d", #base, p, n) << QStringRef(&base) << QLatin1String(#base) << p << n << QStringRef(&r1) << QStringRef(&r2) + + ROW(a, 0, 0, a, empty); + ROW(a, 0, 1, a, a); + ROW(a, 1, 0, empty, empty); + + ROW(ab, 0, 0, ab, empty); + ROW(ab, 0, 1, ab, a); + ROW(ab, 0, 2, ab, ab); + ROW(ab, 1, 0, b, empty); + ROW(ab, 1, 1, b, b); + ROW(ab, 2, 0, empty, empty); + + ROW(abc, 0, 0, abc, empty); + ROW(abc, 0, 1, abc, a); + ROW(abc, 0, 2, abc, ab); + ROW(abc, 0, 3, abc, abc); + ROW(abc, 1, 0, bc, empty); + ROW(abc, 1, 1, bc, b); + ROW(abc, 1, 2, bc, bc); + ROW(abc, 2, 0, c, empty); + ROW(abc, 2, 1, c, c); + ROW(abc, 3, 0, empty, empty); +#undef ROW +} + +template <typename String> +void tst_QStringApiSymmetry::mid_impl() +{ + QFETCH(const QStringRef, unicode); + QFETCH(const QLatin1String, latin1); + QFETCH(const int, pos); + QFETCH(const int, n); + QFETCH(const QStringRef, result); + QFETCH(const QStringRef, result2); + + const auto utf8 = unicode.toUtf8(); + + const auto s = make<String>(unicode, latin1, utf8); + + { + const auto mid = s.mid(pos); + const auto mid2 = s.mid(pos, n); + + QCOMPARE(mid, result); + QCOMPARE(mid.isNull(), result.isNull()); + QCOMPARE(mid.isEmpty(), result.isEmpty()); + + QCOMPARE(mid2, result2); + QCOMPARE(mid2.isNull(), result2.isNull()); + QCOMPARE(mid2.isEmpty(), result2.isEmpty()); + } + { + const auto mid = detached(s).mid(pos); + const auto mid2 = detached(s).mid(pos, n); + + QCOMPARE(mid, result); + QCOMPARE(mid.isNull(), result.isNull()); + QCOMPARE(mid.isEmpty(), result.isEmpty()); + + QCOMPARE(mid2, result2); + QCOMPARE(mid2.isNull(), result2.isNull()); + QCOMPARE(mid2.isEmpty(), result2.isEmpty()); + } +} + +void tst_QStringApiSymmetry::left_data() +{ + QTest::addColumn<QStringRef>("unicode"); + QTest::addColumn<QLatin1String>("latin1"); + QTest::addColumn<int>("n"); + QTest::addColumn<QStringRef>("result"); + + QTest::addRow("null") << QStringRef() << QLatin1String() << 0 << QStringRef(); + QTest::addRow("empty") << QStringRef(&empty) << QLatin1String("") << 0 << QStringRef(&empty); + + // Some classes' left() implementations have a wide contract, others a narrow one + // so only test valid arguents here: +#define ROW(base, n, res) \ + QTest::addRow("%s%d", #base, n) << QStringRef(&base) << QLatin1String(#base) << n << QStringRef(&res); + + ROW(a, 0, empty); + ROW(a, 1, a); + + ROW(ab, 0, empty); + ROW(ab, 1, a); + ROW(ab, 2, ab); + + ROW(abc, 0, empty); + ROW(abc, 1, a); + ROW(abc, 2, ab); + ROW(abc, 3, abc); +#undef ROW +} + +template <typename String> +void tst_QStringApiSymmetry::left_impl() +{ + QFETCH(const QStringRef, unicode); + QFETCH(const QLatin1String, latin1); + QFETCH(const int, n); + QFETCH(const QStringRef, result); + + const auto utf8 = unicode.toUtf8(); + + const auto s = make<String>(unicode, latin1, utf8); + + { + const auto left = s.left(n); + + QCOMPARE(left, result); + QCOMPARE(left.isNull(), result.isNull()); + QCOMPARE(left.isEmpty(), result.isEmpty()); + } + { + const auto left = detached(s).left(n); + + QCOMPARE(left, result); + QCOMPARE(left.isNull(), result.isNull()); + QCOMPARE(left.isEmpty(), result.isEmpty()); + } + { + auto left = s; + left.truncate(n); + + QCOMPARE(left, result); + QCOMPARE(left.isNull(), result.isNull()); + QCOMPARE(left.isEmpty(), result.isEmpty()); + } +} + +void tst_QStringApiSymmetry::right_data() +{ + QTest::addColumn<QStringRef>("unicode"); + QTest::addColumn<QLatin1String>("latin1"); + QTest::addColumn<int>("n"); + QTest::addColumn<QStringRef>("result"); + + QTest::addRow("null") << QStringRef() << QLatin1String() << 0 << QStringRef(); + QTest::addRow("empty") << QStringRef(&empty) << QLatin1String("") << 0 << QStringRef(&empty); + + // Some classes' right() implementations have a wide contract, others a narrow one + // so only test valid arguents here: +#define ROW(base, n, res) \ + QTest::addRow("%s%d", #base, n) << QStringRef(&base) << QLatin1String(#base) << n << QStringRef(&res); + + ROW(a, 0, empty); + ROW(a, 1, a); + + ROW(ab, 0, empty); + ROW(ab, 1, b); + ROW(ab, 2, ab); + + ROW(abc, 0, empty); + ROW(abc, 1, c); + ROW(abc, 2, bc); + ROW(abc, 3, abc); +#undef ROW +} + +template <typename String> +void tst_QStringApiSymmetry::right_impl() +{ + QFETCH(const QStringRef, unicode); + QFETCH(const QLatin1String, latin1); + QFETCH(const int, n); + QFETCH(const QStringRef, result); + + const auto utf8 = unicode.toUtf8(); + + const auto s = make<String>(unicode, latin1, utf8); + + { + const auto right = s.right(n); + + QCOMPARE(right, result); + QCOMPARE(right.isNull(), result.isNull()); + QCOMPARE(right.isEmpty(), result.isEmpty()); + } + { + const auto right = detached(s).right(n); + + QCOMPARE(right, result); + QCOMPARE(right.isNull(), result.isNull()); + QCOMPARE(right.isEmpty(), result.isEmpty()); + } +} + +void tst_QStringApiSymmetry::chop_data() +{ + QTest::addColumn<QStringRef>("unicode"); + QTest::addColumn<QLatin1String>("latin1"); + QTest::addColumn<int>("n"); + QTest::addColumn<QStringRef>("result"); + + QTest::addRow("null") << QStringRef() << QLatin1String() << 0 << QStringRef(); + QTest::addRow("empty") << QStringRef(&empty) << QLatin1String("") << 0 << QStringRef(&empty); + + // Some classes' truncate() implementations have a wide contract, others a narrow one + // so only test valid arguents here: +#define ROW(base, n, res) \ + QTest::addRow("%s%d", #base, n) << QStringRef(&base) << QLatin1String(#base) << n << QStringRef(&res); + + ROW(a, 0, a); + ROW(a, 1, empty); + + ROW(ab, 0, ab); + ROW(ab, 1, a); + ROW(ab, 2, empty); + + ROW(abc, 0, abc); + ROW(abc, 1, ab); + ROW(abc, 2, a); + ROW(abc, 3, empty); +#undef ROW +} + +template <typename String> +void tst_QStringApiSymmetry::chop_impl() +{ + QFETCH(const QStringRef, unicode); + QFETCH(const QLatin1String, latin1); + QFETCH(const int, n); + QFETCH(const QStringRef, result); + + const auto utf8 = unicode.toUtf8(); + + const auto s = make<String>(unicode, latin1, utf8); + + { + const auto chopped = s.chopped(n); + + QCOMPARE(chopped, result); + QCOMPARE(chopped.isNull(), result.isNull()); + QCOMPARE(chopped.isEmpty(), result.isEmpty()); + } + { + const auto chopped = detached(s).chopped(n); + + QCOMPARE(chopped, result); + QCOMPARE(chopped.isNull(), result.isNull()); + QCOMPARE(chopped.isEmpty(), result.isEmpty()); + } + { + auto chopped = s; + chopped.chop(n); + + QCOMPARE(chopped, result); + QCOMPARE(chopped.isNull(), result.isNull()); + QCOMPARE(chopped.isEmpty(), result.isEmpty()); + } +} + +void tst_QStringApiSymmetry::trimmed_data() +{ + QTest::addColumn<QString>("unicode"); + QTest::addColumn<QStringRef>("result"); + + const auto latin1Whitespace = QLatin1String(" \r\n\t\f\v"); + + QTest::addRow("null") << QString() << QStringRef(); + + auto add = [latin1Whitespace](const QString &str) { + // run through all substrings of latin1Whitespace + for (int len = 0; len < latin1Whitespace.size(); ++len) { + for (int pos = 0; pos < latin1Whitespace.size() - len; ++pos) { + const QString unicode = latin1Whitespace.mid(pos, len) + str + latin1Whitespace.mid(pos, len); + const QScopedPointer<const char> escaped(QTest::toString(unicode)); + QTest::addRow("%s", escaped.data()) << unicode << QStringRef(&str); + } + } + }; + + add(empty); + add(a); + add(ab); +} + +template <typename String> +void tst_QStringApiSymmetry::trimmed_impl() +{ + QFETCH(const QString, unicode); + QFETCH(const QStringRef, result); + + const auto utf8 = unicode.toUtf8(); + const auto l1s = unicode.toLatin1(); + const auto l1 = l1s.isNull() ? QLatin1String() : QLatin1String(l1s); + + const auto ref = unicode.isNull() ? QStringRef() : QStringRef(&unicode); + const auto s = make<String>(ref, l1, utf8); + + QCOMPARE(s.isNull(), unicode.isNull()); + + { + const auto trimmed = s.trimmed(); + + QCOMPARE(trimmed, result); + QCOMPARE(trimmed.isNull(), result.isNull()); + QCOMPARE(trimmed.isEmpty(), result.isEmpty()); + } + { + const auto trimmed = detached(s).trimmed(); + + QCOMPARE(trimmed, result); + QCOMPARE(trimmed.isNull(), result.isNull()); + QCOMPARE(trimmed.isEmpty(), result.isEmpty()); + } +} + // // // UTF-16-only checks: @@ -309,6 +1057,7 @@ void tst_QStringApiSymmetry::compare_impl() const template <class Str> Str make(const QString &s); template <> QStringRef make(const QString &s) { return QStringRef(&s); } template <> QString make(const QString &s) { return s; } +template <> QStringView make(const QString &s) { return s; } #define REPEAT_16X(X) X X X X X X X X X X X X X X X X #define LONG_STRING_256 REPEAT_16X("0123456789abcdef") diff --git a/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp b/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp index 319f772516..7d5504c22c 100644 --- a/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp +++ b/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp @@ -326,22 +326,22 @@ void tst_QStringIterator::position() QLatin1Char('p') // codeunit count: 35 }; + static const int stringDataSize = sizeof(stringData) / sizeof(stringData[0]); - const QString string(stringData, sizeof(stringData) / sizeof(stringData[0])); - QStringIterator i(string); + QStringIterator i(QStringView(stringData, stringDataSize)); - QCOMPARE(i.position(), string.constBegin()); + QCOMPARE(i.position(), stringData); QVERIFY(i.hasNext()); QVERIFY(!i.hasPrevious()); - i.setPosition(string.constEnd()); - QCOMPARE(i.position(), string.constEnd()); + i.setPosition(stringData + stringDataSize); + QCOMPARE(i.position(), stringData + stringDataSize); QVERIFY(!i.hasNext()); QVERIFY(i.hasPrevious()); #define QCHAR_UNICODE_VALUE(x) ((uint)(QChar(x).unicode())) - const QString::const_iterator begin = string.constBegin(); + const QChar *begin = stringData; i.setPosition(begin); QCOMPARE(i.position(), begin); QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('a'))); diff --git a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp b/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp index 2385aa992c..9f054190e5 100644 --- a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp +++ b/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp @@ -264,6 +264,15 @@ void tst_QStringList::contains() QVERIFY(list.contains("ARTHUR", Qt::CaseInsensitive)); QVERIFY(list.contains("dent", Qt::CaseInsensitive)); QVERIFY(!list.contains("hans", Qt::CaseInsensitive)); + + QVERIFY(list.contains(QLatin1String("arthur"))); + QVERIFY(!list.contains(QLatin1String("ArthuR"))); + QVERIFY(!list.contains(QLatin1String("Hans"))); + QVERIFY(list.contains(QLatin1String("arthur"), Qt::CaseInsensitive)); + QVERIFY(list.contains(QLatin1String("ArthuR"), Qt::CaseInsensitive)); + QVERIFY(list.contains(QLatin1String("ARTHUR"), Qt::CaseInsensitive)); + QVERIFY(list.contains(QLatin1String("dent"), Qt::CaseInsensitive)); + QVERIFY(!list.contains(QLatin1String("hans"), Qt::CaseInsensitive)); } void tst_QStringList::removeDuplicates_data() diff --git a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp b/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp index d2374fe0ae..473f563f9b 100644 --- a/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp +++ b/tests/auto/corelib/tools/qstringref/tst_qstringref.cpp @@ -1862,7 +1862,9 @@ void tst_QStringRef::double_conversion() void tst_QStringRef::trimmed() { - QString a; + QVERIFY(QStringRef().trimmed().isNull()); + QString a = ""; + QVERIFY(!QStringRef(&a).trimmed().isNull()); QStringRef b; a = "Text"; b = a.leftRef(-1); diff --git a/tests/auto/corelib/tools/qstringview/.gitignore b/tests/auto/corelib/tools/qstringview/.gitignore new file mode 100644 index 0000000000..5f757d448a --- /dev/null +++ b/tests/auto/corelib/tools/qstringview/.gitignore @@ -0,0 +1 @@ +tst_qstringview diff --git a/tests/auto/corelib/tools/qstringview/qstringview.pro b/tests/auto/corelib/tools/qstringview/qstringview.pro new file mode 100644 index 0000000000..e0e9973c91 --- /dev/null +++ b/tests/auto/corelib/tools/qstringview/qstringview.pro @@ -0,0 +1,6 @@ +CONFIG += testcase +TARGET = tst_qstringview +QT = core testlib +contains(QT_CONFIG, c++14):CONFIG *= c++14 +contains(QT_CONFIG, c++1z):CONFIG *= c++1z +SOURCES += tst_qstringview.cpp diff --git a/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp b/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp new file mode 100644 index 0000000000..8a8aa8c6e1 --- /dev/null +++ b/tests/auto/corelib/tools/qstringview/tst_qstringview.cpp @@ -0,0 +1,624 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QStringView> +#include <QString> +#include <QChar> +#include <QStringRef> + +#include <QTest> + +#include <string> + +template <typename T> +using CanConvert = std::is_convertible<T, QStringView>; + +Q_STATIC_ASSERT(!CanConvert<QLatin1String>::value); +Q_STATIC_ASSERT(!CanConvert<const char*>::value); +Q_STATIC_ASSERT(!CanConvert<QByteArray>::value); + +// QStringView qchar_does_not_compile() { return QStringView(QChar('a')); } +// QStringView qlatin1string_does_not_compile() { return QStringView(QLatin1String("a")); } +// QStringView const_char_star_does_not_compile() { return QStringView("a"); } +// QStringView qbytearray_does_not_compile() { return QStringView(QByteArray("a")); } + +// +// QChar +// + +Q_STATIC_ASSERT(!CanConvert<QChar>::value); + +Q_STATIC_ASSERT(CanConvert<QChar[123]>::value); + +Q_STATIC_ASSERT(CanConvert< QString >::value); +Q_STATIC_ASSERT(CanConvert<const QString >::value); +Q_STATIC_ASSERT(CanConvert< QString&>::value); +Q_STATIC_ASSERT(CanConvert<const QString&>::value); + +Q_STATIC_ASSERT(CanConvert< QStringRef >::value); +Q_STATIC_ASSERT(CanConvert<const QStringRef >::value); +Q_STATIC_ASSERT(CanConvert< QStringRef&>::value); +Q_STATIC_ASSERT(CanConvert<const QStringRef&>::value); + + +// +// ushort +// + +Q_STATIC_ASSERT(!CanConvert<ushort>::value); + +Q_STATIC_ASSERT(CanConvert<ushort[123]>::value); + +Q_STATIC_ASSERT(CanConvert< ushort*>::value); +Q_STATIC_ASSERT(CanConvert<const ushort*>::value); + + +// +// char16_t +// + +#if defined(Q_COMPILER_UNICODE_STRINGS) + +Q_STATIC_ASSERT(!CanConvert<char16_t>::value); + +Q_STATIC_ASSERT(CanConvert< char16_t*>::value); +Q_STATIC_ASSERT(CanConvert<const char16_t*>::value); + +#endif + +#if defined(Q_STDLIB_UNICODE_STRINGS) + +Q_STATIC_ASSERT(CanConvert< std::u16string >::value); +Q_STATIC_ASSERT(CanConvert<const std::u16string >::value); +Q_STATIC_ASSERT(CanConvert< std::u16string&>::value); +Q_STATIC_ASSERT(CanConvert<const std::u16string&>::value); + +#endif + + +// +// wchar_t +// + +Q_CONSTEXPR bool CanConvertFromWCharT = +#ifdef Q_OS_WIN + true +#else + false +#endif + ; + +Q_STATIC_ASSERT(!CanConvert<wchar_t>::value); + +Q_STATIC_ASSERT(CanConvert< wchar_t*>::value == CanConvertFromWCharT); +Q_STATIC_ASSERT(CanConvert<const wchar_t*>::value == CanConvertFromWCharT); + +Q_STATIC_ASSERT(CanConvert< std::wstring >::value == CanConvertFromWCharT); +Q_STATIC_ASSERT(CanConvert<const std::wstring >::value == CanConvertFromWCharT); +Q_STATIC_ASSERT(CanConvert< std::wstring&>::value == CanConvertFromWCharT); +Q_STATIC_ASSERT(CanConvert<const std::wstring&>::value == CanConvertFromWCharT); + + +class tst_QStringView : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void constExpr() const; + void basics() const; + void literals() const; + void at() const; + + void fromQString() const; + void fromQStringRef() const; + + void fromQCharStar() const + { + const QChar str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + fromLiteral(str); + } + + void fromUShortStar() const + { + const ushort str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + fromLiteral(str); + } + + void fromChar16TStar() const + { +#if defined(Q_COMPILER_UNICODE_STRINGS) + fromLiteral(u"Hello, World!"); +#else + QSKIP("This test requires C++11 char16_t support enabled in the compiler"); +#endif + } + + void fromWCharTStar() const + { +#ifdef Q_OS_WIN + fromLiteral(L"Hello, World!"); +#else + QSKIP("This is a Windows-only test"); +#endif + } + + void fromQCharRange() const + { + const QChar str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; + fromRange(std::begin(str), std::end(str)); + } + + void fromUShortRange() const + { + const ushort str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; + fromRange(std::begin(str), std::end(str)); + } + + void fromChar16TRange() const + { +#if defined(Q_COMPILER_UNICODE_STRINGS) + const char16_t str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; + fromRange(std::begin(str), std::end(str)); +#else + QSKIP("This test requires C++11 char16_t support enabled in the compiler"); +#endif + } + + void fromWCharTRange() const + { +#ifdef Q_OS_WIN + const wchar_t str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; + fromRange(std::begin(str), std::end(str)); +#else + QSKIP("This is a Windows-only test"); +#endif + } + + // std::basic_string + void fromStdStringWCharT() const + { +#ifdef Q_OS_WIN + fromStdString<wchar_t>(); +#else + QSKIP("This is a Windows-only test"); +#endif + } + void fromStdStringChar16T() const + { +#ifdef Q_STDLIB_UNICODE_STRINGS + fromStdString<char16_t>(); +#else + QSKIP("This test requires C++11 char16_t support enabled in compiler & stdlib"); +#endif + } + +private: + template <typename String> + void conversion_tests(String arg) const; + template <typename Char> + void fromLiteral(const Char *arg) const; + template <typename Char> + void fromRange(const Char *first, const Char *last) const; + template <typename Char, typename Container> + void fromContainer() const; + template <typename Char> + void fromStdString() const { fromContainer<Char, std::basic_string<Char> >(); } +}; + +void tst_QStringView::constExpr() const +{ + // compile-time checks +#ifdef Q_COMPILER_CONSTEXPR + { + constexpr QStringView sv; + Q_STATIC_ASSERT(sv.size() == 0); + Q_STATIC_ASSERT(sv.isNull()); + Q_STATIC_ASSERT(sv.empty()); + Q_STATIC_ASSERT(sv.isEmpty()); + Q_STATIC_ASSERT(sv.utf16() == nullptr); + + constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + Q_STATIC_ASSERT(sv2.isNull()); + Q_STATIC_ASSERT(sv2.empty()); + } + { + constexpr QStringView sv = QStringViewLiteral(""); + Q_STATIC_ASSERT(sv.size() == 0); + Q_STATIC_ASSERT(!sv.isNull()); + Q_STATIC_ASSERT(sv.empty()); + Q_STATIC_ASSERT(sv.isEmpty()); + Q_STATIC_ASSERT(sv.utf16() != nullptr); + + constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + Q_STATIC_ASSERT(!sv2.isNull()); + Q_STATIC_ASSERT(sv2.empty()); + } + { + constexpr QStringView sv = QStringViewLiteral("Hello"); + Q_STATIC_ASSERT(sv.size() == 5); + Q_STATIC_ASSERT(!sv.empty()); + Q_STATIC_ASSERT(!sv.isEmpty()); + Q_STATIC_ASSERT(!sv.isNull()); + Q_STATIC_ASSERT(*sv.utf16() == 'H'); + Q_STATIC_ASSERT(sv[0] == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.at(0) == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.front() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.first() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv[4] == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.at(4) == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.back() == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.last() == QLatin1Char('o')); + + constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + Q_STATIC_ASSERT(!sv2.isNull()); + Q_STATIC_ASSERT(!sv2.empty()); + Q_STATIC_ASSERT(sv2.size() == 5); + } +#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS) + { + Q_STATIC_ASSERT(QStringView(u"Hello").size() == 5); + constexpr QStringView sv = u"Hello"; + Q_STATIC_ASSERT(sv.size() == 5); + Q_STATIC_ASSERT(!sv.empty()); + Q_STATIC_ASSERT(!sv.isEmpty()); + Q_STATIC_ASSERT(!sv.isNull()); + Q_STATIC_ASSERT(*sv.utf16() == 'H'); + Q_STATIC_ASSERT(sv[0] == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.at(0) == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.front() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.first() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv[4] == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.at(4) == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.back() == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.last() == QLatin1Char('o')); + + constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + Q_STATIC_ASSERT(!sv2.isNull()); + Q_STATIC_ASSERT(!sv2.empty()); + Q_STATIC_ASSERT(sv2.size() == 5); + + constexpr char16_t *null = nullptr; + constexpr QStringView sv3(null); + Q_STATIC_ASSERT(sv3.isNull()); + Q_STATIC_ASSERT(sv3.isEmpty()); + Q_STATIC_ASSERT(sv3.size() == 0); + } +#else // storage_type is wchar_t + { + Q_STATIC_ASSERT(QStringView(L"Hello").size() == 5); + constexpr QStringView sv = L"Hello"; + Q_STATIC_ASSERT(sv.size() == 5); + Q_STATIC_ASSERT(!sv.empty()); + Q_STATIC_ASSERT(!sv.isEmpty()); + Q_STATIC_ASSERT(!sv.isNull()); + Q_STATIC_ASSERT(*sv.utf16() == 'H'); + Q_STATIC_ASSERT(sv[0] == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.at(0) == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.front() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv.first() == QLatin1Char('H')); + Q_STATIC_ASSERT(sv[4] == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.at(4) == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.back() == QLatin1Char('o')); + Q_STATIC_ASSERT(sv.last() == QLatin1Char('o')); + + constexpr QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + Q_STATIC_ASSERT(!sv2.isNull()); + Q_STATIC_ASSERT(!sv2.empty()); + Q_STATIC_ASSERT(sv2.size() == 5); + + constexpr wchar_t *null = nullptr; + constexpr QStringView sv3(null); + Q_STATIC_ASSERT(sv3.isNull()); + Q_STATIC_ASSERT(sv3.isEmpty()); + Q_STATIC_ASSERT(sv3.size() == 0); + } +#endif +#endif +} + +void tst_QStringView::basics() const +{ + QStringView sv1; + + // a default-constructed QStringView is null: + QVERIFY(sv1.isNull()); + // which implies it's empty(); + QVERIFY(sv1.isEmpty()); + + QStringView sv2; + + QVERIFY(sv2 == sv1); + QVERIFY(!(sv2 != sv1)); +} + +void tst_QStringView::literals() const +{ +#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS) + const char16_t hello[] = u"Hello"; + const char16_t longhello[] = + u"Hello World. This is a much longer message, to exercise qustrlen."; + const char16_t withnull[] = u"a\0zzz"; +#else // storage_type is wchar_t + const wchar_t hello[] = L"Hello"; + const wchar_t longhello[] = + L"Hello World. This is a much longer message, to exercise qustrlen."; + const wchar_t withnull[] = L"a\0zzz"; +#endif + Q_STATIC_ASSERT(sizeof(longhello) >= 16); + + QCOMPARE(QStringView(hello).size(), 5); + QCOMPARE(QStringView(hello + 0).size(), 5); // forces decay to pointer + QStringView sv = hello; + QCOMPARE(sv.size(), 5); + QVERIFY(!sv.empty()); + QVERIFY(!sv.isEmpty()); + QVERIFY(!sv.isNull()); + QCOMPARE(*sv.utf16(), 'H'); + QCOMPARE(sv[0], QLatin1Char('H')); + QCOMPARE(sv.at(0), QLatin1Char('H')); + QCOMPARE(sv.front(), QLatin1Char('H')); + QCOMPARE(sv.first(), QLatin1Char('H')); + QCOMPARE(sv[4], QLatin1Char('o')); + QCOMPARE(sv.at(4), QLatin1Char('o')); + QCOMPARE(sv.back(), QLatin1Char('o')); + QCOMPARE(sv.last(), QLatin1Char('o')); + + QStringView sv2(sv.utf16(), sv.utf16() + sv.size()); + QVERIFY(!sv2.isNull()); + QVERIFY(!sv2.empty()); + QCOMPARE(sv2.size(), 5); + + QStringView sv3(longhello); + QCOMPARE(size_t(sv3.size()), sizeof(longhello)/sizeof(longhello[0]) - 1); + QCOMPARE(sv3.last(), QLatin1Char('.')); + sv3 = longhello; + QCOMPARE(size_t(sv3.size()), sizeof(longhello)/sizeof(longhello[0]) - 1); + + for (int i = 0; i < sv3.size(); ++i) { + QStringView sv4(longhello + i); + QCOMPARE(size_t(sv4.size()), sizeof(longhello)/sizeof(longhello[0]) - 1 - i); + QCOMPARE(sv4.last(), QLatin1Char('.')); + sv4 = longhello + i; + QCOMPARE(size_t(sv4.size()), sizeof(longhello)/sizeof(longhello[0]) - 1 - i); + } + + // these are different results + QCOMPARE(size_t(QStringView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1); + QCOMPARE(QStringView(withnull + 0).size(), 1); +} + +void tst_QStringView::at() const +{ + QString hello("Hello"); + QStringView sv(hello); + QCOMPARE(sv.at(0), QChar('H')); QCOMPARE(sv[0], QChar('H')); + QCOMPARE(sv.at(1), QChar('e')); QCOMPARE(sv[1], QChar('e')); + QCOMPARE(sv.at(2), QChar('l')); QCOMPARE(sv[2], QChar('l')); + QCOMPARE(sv.at(3), QChar('l')); QCOMPARE(sv[3], QChar('l')); + QCOMPARE(sv.at(4), QChar('o')); QCOMPARE(sv[4], QChar('o')); +} + +void tst_QStringView::fromQString() const +{ + QString null; + QString empty = ""; + + QVERIFY( QStringView(null).isNull()); + QVERIFY( QStringView(null).isEmpty()); + QVERIFY( QStringView(empty).isEmpty()); + QVERIFY(!QStringView(empty).isNull()); + + conversion_tests(QString("Hello World!")); +} + +void tst_QStringView::fromQStringRef() const +{ + QStringRef null; + QString emptyS = ""; + QStringRef empty(&emptyS); + + QVERIFY( QStringView(null).isNull()); + QVERIFY( QStringView(null).isEmpty()); + QVERIFY( QStringView(empty).isEmpty()); + QVERIFY(!QStringView(empty).isNull()); + + conversion_tests(QString("Hello World!").midRef(6)); +} + +template <typename Char> +void tst_QStringView::fromLiteral(const Char *arg) const +{ + const Char *null = nullptr; + const Char empty[] = { 0 }; + + QCOMPARE(QStringView(null).size(), qsizetype(0)); + QCOMPARE(QStringView(null).data(), nullptr); + QCOMPARE(QStringView(empty).size(), qsizetype(0)); + QCOMPARE(static_cast<const void*>(QStringView(empty).data()), + static_cast<const void*>(empty)); + + QVERIFY( QStringView(null).isNull()); + QVERIFY( QStringView(null).isEmpty()); + QVERIFY( QStringView(empty).isEmpty()); + QVERIFY(!QStringView(empty).isNull()); + + conversion_tests(arg); +} + +template <typename Char> +void tst_QStringView::fromRange(const Char *first, const Char *last) const +{ + const Char *null = nullptr; + QCOMPARE(QStringView(null, null).size(), 0); + QCOMPARE(QStringView(null, null).data(), nullptr); + QCOMPARE(QStringView(first, first).size(), 0); + QCOMPARE(static_cast<const void*>(QStringView(first, first).data()), + static_cast<const void*>(first)); + + const auto sv = QStringView(first, last); + QCOMPARE(sv.size(), last - first); + QCOMPARE(static_cast<const void*>(sv.data()), + static_cast<const void*>(first)); + + // can't call conversion_tests() here, as it requires a single object +} + +template <typename Char, typename Container> +void tst_QStringView::fromContainer() const +{ + const QString s = "Hello World!"; + + Container c; + // unspecified whether empty containers make null QStringViews + QVERIFY(QStringView(c).isEmpty()); + + QCOMPARE(sizeof(Char), sizeof(QChar)); + + const auto *data = reinterpret_cast<const Char *>(s.utf16()); + std::copy(data, data + s.size(), std::back_inserter(c)); + conversion_tests(std::move(c)); +} + +namespace help { +template <typename T> +size_t size(const T &t) { return size_t(t.size()); } +template <typename T> +size_t size(const T *t) +{ + size_t result = 0; + if (t) { + while (*t++) + ++result; + } + return result; +} +size_t size(const QChar *t) +{ + size_t result = 0; + if (t) { + while (!t++->isNull()) + ++result; + } + return result; +} + +template <typename T> +typename T::const_iterator cbegin(const T &t) { return t.cbegin(); } +template <typename T> +const T * cbegin(const T *t) { return t; } + +template <typename T> +typename T::const_iterator cend(const T &t) { return t.cend(); } +template <typename T> +const T * cend(const T *t) { return t + size(t); } + +template <typename T> +typename T::const_reverse_iterator crbegin(const T &t) { return t.crbegin(); } +template <typename T> +std::reverse_iterator<const T*> crbegin(const T *t) { return std::reverse_iterator<const T*>(cend(t)); } + +template <typename T> +typename T::const_reverse_iterator crend(const T &t) { return t.crend(); } +template <typename T> +std::reverse_iterator<const T*> crend(const T *t) { return std::reverse_iterator<const T*>(cbegin(t)); } + +} // namespace help + +template <typename String> +void tst_QStringView::conversion_tests(String string) const +{ + // copy-construct: + { + QStringView sv = string; + + QCOMPARE(help::size(sv), help::size(string)); + + // check iterators: + + QVERIFY(std::equal(help::cbegin(string), help::cend(string), + QT_MAKE_CHECKED_ARRAY_ITERATOR(sv.cbegin(), sv.size()))); + QVERIFY(std::equal(help::cbegin(string), help::cend(string), + QT_MAKE_CHECKED_ARRAY_ITERATOR(sv.begin(), sv.size()))); + QVERIFY(std::equal(help::crbegin(string), help::crend(string), + sv.crbegin())); + QVERIFY(std::equal(help::crbegin(string), help::crend(string), + sv.rbegin())); + + QCOMPARE(sv, string); + } + + QStringView sv; + + // copy-assign: + { + sv = string; + + QCOMPARE(help::size(sv), help::size(string)); + + // check relational operators: + + QCOMPARE(sv, string); + QCOMPARE(string, sv); + + QVERIFY(!(sv != string)); + QVERIFY(!(string != sv)); + + QVERIFY(!(sv < string)); + QVERIFY(sv <= string); + QVERIFY(!(sv > string)); + QVERIFY(sv >= string); + + QVERIFY(!(string < sv)); + QVERIFY(string <= sv); + QVERIFY(!(string > sv)); + QVERIFY(string >= sv); + } + + // copy-construct from rvalue (QStringView never assumes ownership): + { + QStringView sv2 = std::move(string); + QCOMPARE(sv2, sv); + QCOMPARE(sv2, string); + } + + // copy-assign from rvalue (QStringView never assumes ownership): + { + QStringView sv2; + sv2 = std::move(string); + QCOMPARE(sv2, sv); + QCOMPARE(sv2, string); + } +} + +QTEST_APPLESS_MAIN(tst_QStringView) +#include "tst_qstringview.moc" diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp index e75ed5cc67..9f22c3d51d 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp @@ -62,7 +62,9 @@ private slots: private: void printTimeZone(const QTimeZone &tz); #ifdef QT_BUILD_INTERNAL + // Generic tests of privates, called by implementation-specific private tests: void testCetPrivate(const QTimeZonePrivate &tzp); + void testEpochTranPrivate(const QTimeZonePrivate &tzp); #endif // QT_BUILD_INTERNAL const bool debug; }; @@ -167,11 +169,11 @@ void tst_QTimeZone::createTest() QDateTime jun = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC); QDateTime janPrev = QDateTime(QDate(2011, 1, 1), QTime(0, 0, 0), Qt::UTC); - QCOMPARE(tz.offsetFromUtc(jan), 46800); - QCOMPARE(tz.offsetFromUtc(jun), 43200); + QCOMPARE(tz.offsetFromUtc(jan), 13 * 3600); + QCOMPARE(tz.offsetFromUtc(jun), 12 * 3600); - QCOMPARE(tz.standardTimeOffset(jan), 43200); - QCOMPARE(tz.standardTimeOffset(jun), 43200); + QCOMPARE(tz.standardTimeOffset(jan), 12 * 3600); + QCOMPARE(tz.standardTimeOffset(jun), 12 * 3600); QCOMPARE(tz.daylightTimeOffset(jan), 3600); QCOMPARE(tz.daylightTimeOffset(jun), 0); @@ -183,38 +185,46 @@ void tst_QTimeZone::createTest() // Only test transitions if host system supports them if (tz.hasTransitions()) { QTimeZone::OffsetData tran = tz.nextTransition(jan); - QCOMPARE(tran.atUtc.toMSecsSinceEpoch(), (qint64)1333202400000); - QCOMPARE(tran.offsetFromUtc, 43200); - QCOMPARE(tran.standardTimeOffset, 43200); + // 2012-04-01 03:00 NZDT, +13 -> +12 + QCOMPARE(tran.atUtc, + QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600)); + QCOMPARE(tran.offsetFromUtc, 12 * 3600); + QCOMPARE(tran.standardTimeOffset, 12 * 3600); QCOMPARE(tran.daylightTimeOffset, 0); tran = tz.nextTransition(jun); - QCOMPARE(tran.atUtc.toMSecsSinceEpoch(), (qint64)1348927200000); - QCOMPARE(tran.offsetFromUtc, 46800); - QCOMPARE(tran.standardTimeOffset, 43200); + // 2012-09-30 02:00 NZST, +12 -> +13 + QCOMPARE(tran.atUtc, + QDateTime(QDate(2012, 9, 30), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600)); + QCOMPARE(tran.offsetFromUtc, 13 * 3600); + QCOMPARE(tran.standardTimeOffset, 12 * 3600); QCOMPARE(tran.daylightTimeOffset, 3600); tran = tz.previousTransition(jan); - QCOMPARE(tran.atUtc.toMSecsSinceEpoch(), (qint64)1316872800000); - QCOMPARE(tran.offsetFromUtc, 46800); - QCOMPARE(tran.standardTimeOffset, 43200); + // 2011-09-25 02:00 NZST, +12 -> +13 + QCOMPARE(tran.atUtc, + QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600)); + QCOMPARE(tran.offsetFromUtc, 13 * 3600); + QCOMPARE(tran.standardTimeOffset, 12 * 3600); QCOMPARE(tran.daylightTimeOffset, 3600); tran = tz.previousTransition(jun); - QCOMPARE(tran.atUtc.toMSecsSinceEpoch(), (qint64)1333202400000); - QCOMPARE(tran.offsetFromUtc, 43200); - QCOMPARE(tran.standardTimeOffset, 43200); + // 2012-04-01 03:00 NZDT, +13 -> +12 (again) + QCOMPARE(tran.atUtc, + QDateTime(QDate(2012, 4, 1), QTime(3, 0), Qt::OffsetFromUTC, 13 * 3600)); + QCOMPARE(tran.offsetFromUtc, 12 * 3600); + QCOMPARE(tran.standardTimeOffset, 12 * 3600); QCOMPARE(tran.daylightTimeOffset, 0); QTimeZone::OffsetDataList expected; - tran.atUtc = QDateTime::fromMSecsSinceEpoch(1301752800000, Qt::UTC); - tran.offsetFromUtc = 46800; - tran.standardTimeOffset = 43200; + tran.atUtc = QDateTime(QDate(2011, 4, 3), QTime(2, 0), Qt::OffsetFromUTC, 13 * 3600); + tran.offsetFromUtc = 13 * 3600; + tran.standardTimeOffset = 12 * 3600; tran.daylightTimeOffset = 3600; expected << tran; - tran.atUtc = QDateTime::fromMSecsSinceEpoch(1316872800000, Qt::UTC); - tran.offsetFromUtc = 43200; - tran.standardTimeOffset = 43200; + tran.atUtc = QDateTime(QDate(2011, 9, 25), QTime(2, 0), Qt::OffsetFromUTC, 12 * 3600); + tran.offsetFromUtc = 12 * 3600; + tran.standardTimeOffset = 12 * 3600; tran.daylightTimeOffset = 0; expected << tran; QTimeZone::OffsetDataList result = tz.transitions(janPrev, jan); @@ -749,12 +759,13 @@ void tst_QTimeZone::icuTest() } testCetPrivate(tzp); + testEpochTranPrivate(QIcuTimeZonePrivate("America/Toronto")); #endif // QT_USE_ICU } void tst_QTimeZone::tzTest() { -#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_MAC +#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN // Known datetimes qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); @@ -822,6 +833,7 @@ void tst_QTimeZone::tzTest() } testCetPrivate(tzp); + testEpochTranPrivate(QTzTimeZonePrivate("America/Toronto")); // Test first and last transition rule // Warning: This could vary depending on age of TZ file! @@ -845,7 +857,8 @@ void tst_QTimeZone::tzTest() } dat = tzp.nextTransition(-9999999999999); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)-2422054408000); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), + QDateTime(QDate(1893, 4, 1), QTime(0, 6, 32), Qt::OffsetFromUTC, 3600)); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 0); @@ -855,37 +868,41 @@ void tst_QTimeZone::tzTest() // Tets high dates use the POSIX rule dat = tzp.data(stdHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)stdHi); + QCOMPARE(dat.atMSecsSinceEpoch - stdHi, (qint64)0); QCOMPARE(dat.offsetFromUtc, 3600); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 0); dat = tzp.data(dstHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)dstHi); + QCOMPARE(dat.atMSecsSinceEpoch - dstHi, (qint64)0); QCOMPARE(dat.offsetFromUtc, 7200); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 3600); dat = tzp.previousTransition(stdHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)4096659600000); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), + QDateTime(QDate(2099, 10, 26), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(dat.offsetFromUtc, 3600); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 0); dat = tzp.previousTransition(dstHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)4109965200000); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), + QDateTime(QDate(2100, 3, 29), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(dat.offsetFromUtc, 7200); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 3600); dat = tzp.nextTransition(stdHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)4109965200000); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), + QDateTime(QDate(2100, 3, 29), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(dat.offsetFromUtc, 7200); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 3600); dat = tzp.nextTransition(dstHi); - QCOMPARE(dat.atMSecsSinceEpoch, (qint64)4128109200000); + QCOMPARE(QDateTime::fromMSecsSinceEpoch(dat.atMSecsSinceEpoch, Qt::OffsetFromUTC, 3600), + QDateTime(QDate(2100, 10, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(dat.offsetFromUtc, 3600); QCOMPARE(dat.standardTimeOffset, 3600); QCOMPARE(dat.daylightTimeOffset, 0); @@ -917,12 +934,12 @@ void tst_QTimeZone::tzTest() QDateTime dt(QDate(2016, 3, 28), QTime(0, 0, 0), Qt::UTC); QCOMPARE(tzBarnaul.data(dt.toMSecsSinceEpoch()).abbreviation, QString("+07")); } -#endif // Q_OS_UNIX +#endif // QT_BUILD_INTERNAL && Q_OS_UNIX && !Q_OS_DARWIN } void tst_QTimeZone::macTest() { -#if defined(QT_BUILD_INTERNAL) && defined (Q_OS_MAC) +#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_DARWIN) // Known datetimes qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); @@ -969,7 +986,8 @@ void tst_QTimeZone::macTest() } testCetPrivate(tzp); -#endif // Q_OS_MAC + testEpochTranPrivate(QMacTimeZonePrivate("America/Toronto")); +#endif // QT_BUILD_INTERNAL && Q_OS_DARWIN } void tst_QTimeZone::darwinTypes() @@ -1034,6 +1052,7 @@ void tst_QTimeZone::winTest() } testCetPrivate(tzp); + testEpochTranPrivate(QWinTimeZonePrivate("America/Toronto")); #endif // Q_OS_WIN } @@ -1076,50 +1095,103 @@ void tst_QTimeZone::testCetPrivate(const QTimeZonePrivate &tzp) // Only test transitions if host system supports them if (tzp.hasTransitions()) { QTimeZonePrivate::Data tran = tzp.nextTransition(std); - QCOMPARE(tran.atMSecsSinceEpoch, (qint64)1332637200000); + // 2012-03-25 02:00 CET, +1 -> +2 + QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), + QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(tran.offsetFromUtc, 7200); QCOMPARE(tran.standardTimeOffset, 3600); QCOMPARE(tran.daylightTimeOffset, 3600); tran = tzp.nextTransition(dst); - QCOMPARE(tran.atMSecsSinceEpoch, (qint64)1351386000000); + // 2012-10-28 03:00 CEST, +2 -> +1 + QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), + QDateTime(QDate(2012, 10, 28), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600)); QCOMPARE(tran.offsetFromUtc, 3600); QCOMPARE(tran.standardTimeOffset, 3600); QCOMPARE(tran.daylightTimeOffset, 0); tran = tzp.previousTransition(std); - QCOMPARE(tran.atMSecsSinceEpoch, (qint64)1319936400000); + // 2011-10-30 03:00 CEST, +2 -> +1 + QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), + QDateTime(QDate(2011, 10, 30), QTime(3, 0), Qt::OffsetFromUTC, 2 * 3600)); QCOMPARE(tran.offsetFromUtc, 3600); QCOMPARE(tran.standardTimeOffset, 3600); QCOMPARE(tran.daylightTimeOffset, 0); tran = tzp.previousTransition(dst); - QCOMPARE(tran.atMSecsSinceEpoch, (qint64)1332637200000); + // 2012-03-25 02:00 CET, +1 -> +2 (again) + QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), + QDateTime(QDate(2012, 3, 25), QTime(2, 0), Qt::OffsetFromUTC, 3600)); QCOMPARE(tran.offsetFromUtc, 7200); QCOMPARE(tran.standardTimeOffset, 3600); QCOMPARE(tran.daylightTimeOffset, 3600); QTimeZonePrivate::DataList expected; - tran.atMSecsSinceEpoch = (qint64)1301752800000; + // 2011-03-27 02:00 CET, +1 -> +2 + tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 3, 27), QTime(2, 0), + Qt::OffsetFromUTC, 3600).toMSecsSinceEpoch(); tran.offsetFromUtc = 7200; tran.standardTimeOffset = 3600; tran.daylightTimeOffset = 3600; expected << tran; - tran.atMSecsSinceEpoch = (qint64)1316872800000; + // 2011-10-30 03:00 CEST, +2 -> +1 + tran.atMSecsSinceEpoch = QDateTime(QDate(2011, 10, 30), QTime(3, 0), + Qt::OffsetFromUTC, 2 * 3600).toMSecsSinceEpoch(); tran.offsetFromUtc = 3600; tran.standardTimeOffset = 3600; tran.daylightTimeOffset = 0; expected << tran; QTimeZonePrivate::DataList result = tzp.transitions(prev, std); QCOMPARE(result.count(), expected.count()); - for (int i = 0; i > expected.count(); ++i) { - QCOMPARE(result.at(i).atMSecsSinceEpoch, expected.at(i).atMSecsSinceEpoch); + for (int i = 0; i < expected.count(); ++i) { + QCOMPARE(QDateTime::fromMSecsSinceEpoch(result.at(i).atMSecsSinceEpoch, + Qt::OffsetFromUTC, 3600), + QDateTime::fromMSecsSinceEpoch(expected.at(i).atMSecsSinceEpoch, + Qt::OffsetFromUTC, 3600)); QCOMPARE(result.at(i).offsetFromUtc, expected.at(i).offsetFromUtc); QCOMPARE(result.at(i).standardTimeOffset, expected.at(i).standardTimeOffset); QCOMPARE(result.at(i).daylightTimeOffset, expected.at(i).daylightTimeOffset); } } } + +// Needs a zone with DST around the epoch; currently America/Toronto (EST5EDT) +void tst_QTimeZone::testEpochTranPrivate(const QTimeZonePrivate &tzp) +{ + if (!tzp.hasTransitions()) + return; // test only viable for transitions + + QTimeZonePrivate::Data tran = tzp.nextTransition(0); // i.e. first after epoch + // 1970-04-26 02:00 EST, -5 -> -4 + const QDateTime after = QDateTime(QDate(1970, 4, 26), QTime(2, 0), Qt::OffsetFromUTC, -5 * 3600); + const QDateTime found = QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC); +#ifdef Q_OS_WIN // MS gets the date wrong: 5th April instead of 26th. + QCOMPARE(found.toOffsetFromUtc(-5 * 3600).time(), after.time()); +#else + QCOMPARE(found, after); +#endif + QCOMPARE(tran.offsetFromUtc, -4 * 3600); + QCOMPARE(tran.standardTimeOffset, -5 * 3600); + QCOMPARE(tran.daylightTimeOffset, 3600); + + // Pre-epoch time-zones might not be supported at all: + tran = tzp.nextTransition(QDateTime(QDate(1601, 1, 1), QTime(0, 0), + Qt::UTC).toMSecsSinceEpoch()); + if (tran.atMSecsSinceEpoch != QTimeZonePrivate::invalidSeconds() + && tran.atMSecsSinceEpoch < 0) { + // ... but, if they are, we should be able to search back to them: + tran = tzp.previousTransition(0); // i.e. last before epoch + // 1969-10-26 02:00 EDT, -4 -> -5 + QCOMPARE(QDateTime::fromMSecsSinceEpoch(tran.atMSecsSinceEpoch, Qt::UTC), + QDateTime(QDate(1969, 10, 26), QTime(2, 0), Qt::OffsetFromUTC, -4 * 3600)); + QCOMPARE(tran.offsetFromUtc, -5 * 3600); + QCOMPARE(tran.standardTimeOffset, -5 * 3600); + QCOMPARE(tran.daylightTimeOffset, 0); + } else { + // Do not use QSKIP(): that would discard the rest of this sub-test's caller. + qDebug() << "No support for pre-epoch time-zone transitions"; + } +} #endif // QT_BUILD_INTERNAL QTEST_APPLESS_MAIN(tst_QTimeZone) diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 0806ad1318..3971353cbb 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -30,8 +30,6 @@ #include <qvarlengtharray.h> #include <qvariant.h> -const int N = 1; - class tst_QVarLengthArray : public QObject { Q_OBJECT diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp index 2e34e82388..9812d93a50 100644 --- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp +++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp @@ -513,6 +513,14 @@ void tst_QVersionNumber::fromString() QCOMPARE(QVersionNumber::fromString(constructionString), expectedVersion); QCOMPARE(QVersionNumber::fromString(constructionString, &index), expectedVersion); QCOMPARE(index, suffixIndex); + + QCOMPARE(QVersionNumber::fromString(QStringView(constructionString)), expectedVersion); + QCOMPARE(QVersionNumber::fromString(QStringView(constructionString), &index), expectedVersion); + QCOMPARE(index, suffixIndex); + + QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1())), expectedVersion); + QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &index), expectedVersion); + QCOMPARE(index, suffixIndex); } void tst_QVersionNumber::toString_data() diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index e45771a704..f35ed026ac 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -1,6 +1,7 @@ TEMPLATE=subdirs SUBDIRS=\ collections \ + containerapisymmetry \ qalgorithms \ qarraydata \ qarraydata_strictiterators \ @@ -56,6 +57,7 @@ SUBDIRS=\ qstringlist \ qstringmatcher \ qstringref \ + qstringview \ qtextboundaryfinder \ qtime \ qtimezone \ @@ -65,3 +67,4 @@ SUBDIRS=\ qvector_strictiterators \ qversionnumber +darwin: SUBDIRS += qmacautoreleasepool |