diff options
Diffstat (limited to 'tests/auto/corelib/tools/qvarlengtharray')
-rw-r--r-- | tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt | 9 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp | 330 |
2 files changed, 280 insertions, 59 deletions
diff --git a/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt b/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt index bdc927d5b6..eccb2634cc 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt +++ b/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qvarlengtharray.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qvarlengtharray Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qvarlengtharray LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qvarlengtharray SOURCES tst_qvarlengtharray.cpp diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 0598a39cb6..6a92663bc4 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -1,36 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QTest> -#include <qvarlengtharray.h> +#include <QVarLengthArray> #include <qvariant.h> #include <qscopeguard.h> +#include <qscopedvaluerollback.h> +#include <algorithm> +#include <q20iterator.h> #include <memory> struct Tracker @@ -64,12 +42,34 @@ public: { return !operator==(lhs, rhs); } }; +class NonCopyable +{ + Q_DISABLE_COPY(NonCopyable) + int n; +public: + NonCopyable() : n(0) {} + explicit NonCopyable(int n) : n(n) {} + + friend bool operator==(const NonCopyable &lhs, const NonCopyable &rhs) noexcept + { return lhs.n == rhs.n; } + friend bool operator!=(const NonCopyable &lhs, const NonCopyable &rhs) noexcept + { return !operator==(lhs, rhs); } +}; + class tst_QVarLengthArray : public QObject { Q_OBJECT private slots: + void defaultConstructor_int() { defaultConstructor<int>(); } + void defaultConstructor_QString() { defaultConstructor<QString>(); } + void sizeConstructor_int() { sizeConstructor<int>(); } + void sizeConstructor_QString() { sizeConstructor<QString>(); } + void sizeConstructor_NonCopyable() { sizeConstructor<NonCopyable>(); } void append(); + void preallocatedSize(); +#if QT_DEPRECATED_SINCE(6, 3) void prepend(); +#endif void emplace(); void move_int_1() { move_int<1>(); } void move_int_2() { move_int<2>(); } @@ -83,6 +83,7 @@ private slots: void removeLast(); void oldTests(); void appendCausingRealloc(); + void appendIsStronglyExceptionSafe(); void resize(); void realloc(); void iterators(); @@ -111,7 +112,13 @@ private slots: void remove(); void erase(); + // special cases: + void copesWithCopyabilityOfMoveOnlyVector(); // QTBUG-109745 private: + template <typename T> + void defaultConstructor(); + template <typename T> + void sizeConstructor(); template <qsizetype N, typename T> void move(T t1, T t2); template <qsizetype N> @@ -124,6 +131,48 @@ private: void initializeList(); }; +template <typename T> +void tst_QVarLengthArray::defaultConstructor() +{ + { + QVarLengthArray<T, 123> vla; + QCOMPARE(vla.size(), 0); + QVERIFY(vla.empty()); + QVERIFY(vla.isEmpty()); + QCOMPARE(vla.begin(), vla.end()); + QCOMPARE(vla.capacity(), 123); + } + { + QVarLengthArray<T> vla; + QCOMPARE(vla.capacity(), 256); // notice, should we change the default + } +} + +template <typename T> +void tst_QVarLengthArray::sizeConstructor() +{ + { + QVarLengthArray<T, 123> vla(0); + QCOMPARE(vla.size(), 0); + QVERIFY(vla.empty()); + QVERIFY(vla.isEmpty()); + QCOMPARE(vla.begin(), vla.end()); + QCOMPARE(vla.capacity(), 123); + } + { + QVarLengthArray<T, 124> vla(124); + QCOMPARE(vla.size(), 124); + QVERIFY(!vla.empty()); + QCOMPARE(vla.capacity(), 124); + } + { + QVarLengthArray<T, 124> vla(125); + QCOMPARE(vla.size(), 125); + QVERIFY(!vla.empty()); + QCOMPARE_GE(vla.capacity(), 125); + } +} + void tst_QVarLengthArray::append() { QVarLengthArray<QString, 2> v; @@ -146,6 +195,18 @@ void tst_QVarLengthArray::append() v2.append(5); } +void tst_QVarLengthArray::preallocatedSize() +{ + // The default is 256: + static_assert(QVarLengthArray<int>::PreallocatedSize == 256); + // Otherwise, whatever was given as template argument: + static_assert(QVarLengthArray<int, 42>::PreallocatedSize == 42); + static_assert(QVarLengthArray<int, 1'000'000>::PreallocatedSize == 1'000'000); +} + +#if QT_DEPRECATED_SINCE(6, 3) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void tst_QVarLengthArray::prepend() { QVarLengthArray<QString, 2> v; @@ -164,6 +225,8 @@ void tst_QVarLengthArray::prepend() v.prepend(v.back()); QCOMPARE(v.front(), v.back()); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 3) void tst_QVarLengthArray::emplace() { @@ -180,6 +243,33 @@ void tst_QVarLengthArray::emplace() QCOMPARE(&r, &strings.back()); QCOMPARE(strings.size(), 3); QCOMPARE(strings.back(), QString(42, u'y')); + + // test growing from empty arrays + QVarLengthArray<QString> emptyArrDefaultPrealloc; + QCOMPARE(emptyArrDefaultPrealloc.size(), 0); + emptyArrDefaultPrealloc.emplace_back(); + QCOMPARE(emptyArrDefaultPrealloc.size(), 1); + emptyArrDefaultPrealloc.resize(1024); + QCOMPARE(emptyArrDefaultPrealloc.size(), 1024); + emptyArrDefaultPrealloc.resize(0); + QCOMPARE(emptyArrDefaultPrealloc.size(), 0); + emptyArrDefaultPrealloc.squeeze(); + QCOMPARE(emptyArrDefaultPrealloc.size(), 0); + emptyArrDefaultPrealloc.emplace_back(); + QCOMPARE(emptyArrDefaultPrealloc.size(), 1); + + QVarLengthArray<QString, 1> emptyArrSmallPrealloc; + QCOMPARE(emptyArrSmallPrealloc.size(), 0); + emptyArrSmallPrealloc.emplace_back(); + QCOMPARE(emptyArrSmallPrealloc.size(), 1); + emptyArrSmallPrealloc.resize(1024); + QCOMPARE(emptyArrSmallPrealloc.size(), 1024); + emptyArrSmallPrealloc.resize(0); + QCOMPARE(emptyArrSmallPrealloc.size(), 0); + emptyArrSmallPrealloc.squeeze(); + QCOMPARE(emptyArrSmallPrealloc.size(), 0); + emptyArrSmallPrealloc.emplace_back(); + QCOMPARE(emptyArrSmallPrealloc.size(), 1); } } @@ -352,6 +442,80 @@ void tst_QVarLengthArray::appendCausingRealloc() QVarLengthArray<float, 1> d(1); for (int i=0; i<30; i++) d.append(i); + + // Regression test for QTBUG-110412: + constexpr qsizetype InitialCapacity = 10; + QVarLengthArray<float, InitialCapacity> d2(InitialCapacity); + std::iota(d2.begin(), d2.end(), 0.0f); + QCOMPARE_EQ(d2.size(), d2.capacity()); // by construction + float floats[1000]; + std::iota(std::begin(floats), std::end(floats), InitialCapacity + 0.0f); + d2.append(floats, q20::ssize(floats)); + QCOMPARE_EQ(d2.size(), q20::ssize(floats) + InitialCapacity); + QCOMPARE_GE(d2.capacity(), d2.size()); +} + +void tst_QVarLengthArray::appendIsStronglyExceptionSafe() +{ +#ifdef QT_NO_EXCEPTIONS + QSKIP("This test requires exception support enabled in the compiler."); +#else + static bool throwOnCopyNow = false; + static bool throwOnMoveNow = false; + struct Thrower { + Thrower() = default; + Thrower(const Thrower &) + { + if (throwOnCopyNow) + throw 1; + } + Thrower &operator=(const Thrower &) = default; + Thrower(Thrower &&) + { + if (throwOnMoveNow) + throw 1; + } + Thrower &operator=(Thrower &&) = default; + ~Thrower() = default; + }; + + { + QVarLengthArray<Thrower, 2> vla(1); + { + Thrower t; + const QScopedValueRollback rb(throwOnCopyNow, true); + QVERIFY_THROWS_EXCEPTION(int, vla.push_back(t)); + QCOMPARE(vla.size(), 1); + } + { + const QScopedValueRollback rb(throwOnMoveNow, true); + QVERIFY_THROWS_EXCEPTION(int, vla.push_back({})); + QCOMPARE(vla.size(), 1); + } + vla.push_back({}); + QCOMPARE(vla.size(), 2); + { + Thrower t; + { + // tests the copy inside append() + const QScopedValueRollback rb(throwOnCopyNow, true); + QVERIFY_THROWS_EXCEPTION(int, vla.push_back(t)); + QCOMPARE(vla.size(), 2); + } + { + // tests the move inside reallocate() + const QScopedValueRollback rb(throwOnMoveNow, true); + QVERIFY_THROWS_EXCEPTION(int, vla.push_back(t)); + QCOMPARE(vla.size(), 2); + } + } + { + const QScopedValueRollback rb(throwOnMoveNow, true); + QVERIFY_THROWS_EXCEPTION(int, vla.push_back({})); + QCOMPARE(vla.size(), 2); + } + } +#endif } void tst_QVarLengthArray::resize() @@ -480,6 +644,12 @@ struct MyBase bool hasMoved() const { return !wasConstructedAt(this); } protected: + void swap(MyBase &other) { + using std::swap; + swap(data, other.data); + swap(isCopy, other.isCopy); + } + MyBase(const MyBase *data, bool isCopy) : data(data), isCopy(isCopy) {} @@ -554,6 +724,14 @@ struct MyMovable return *this; } + void swap(MyMovable &other) noexcept + { + MyBase::swap(other); + std::swap(i, other.i); + } + + friend void swap(MyMovable &lhs, MyMovable &rhs) noexcept { lhs.swap(rhs); } + bool operator==(const MyMovable &other) const { return i == other.i; @@ -569,6 +747,15 @@ struct MyComplex { return i == other.i; } + + void swap(MyComplex &other) noexcept + { + MyBase::swap(other); + std::swap(i, other.i); + } + + friend void swap(MyComplex &lhs, MyComplex &rhs) noexcept { lhs.swap(rhs); } + char i; }; @@ -841,8 +1028,8 @@ void tst_QVarLengthArray::count() // tests size(), count() and length(), since they're the same thing { const QVarLengthArray<int> list; - QCOMPARE(list.length(), 0); - QCOMPARE(list.count(), 0); + QCOMPARE(list.size(), 0); + QCOMPARE(list.size(), 0); QCOMPARE(list.size(), 0); QVERIFY(list.isEmpty()); } @@ -850,8 +1037,8 @@ void tst_QVarLengthArray::count() { QVarLengthArray<int> list; list.append(0); - QCOMPARE(list.length(), 1); - QCOMPARE(list.count(), 1); + QCOMPARE(list.size(), 1); + QCOMPARE(list.size(), 1); QCOMPARE(list.size(), 1); QVERIFY(!list.isEmpty()); } @@ -860,8 +1047,8 @@ void tst_QVarLengthArray::count() QVarLengthArray<int> list; list.append(0); list.append(1); - QCOMPARE(list.length(), 2); - QCOMPARE(list.count(), 2); + QCOMPARE(list.size(), 2); + QCOMPARE(list.size(), 2); QCOMPARE(list.size(), 2); QVERIFY(!list.isEmpty()); } @@ -871,8 +1058,8 @@ void tst_QVarLengthArray::count() list.append(0); list.append(0); list.append(0); - QCOMPARE(list.length(), 3); - QCOMPARE(list.count(), 3); + QCOMPARE(list.size(), 3); + QCOMPARE(list.size(), 3); QCOMPARE(list.size(), 3); QVERIFY(!list.isEmpty()); } @@ -883,23 +1070,23 @@ void tst_QVarLengthArray::count() list.append(0); list.append(0); list.append(0); - QCOMPARE(list.length(), 3); - QCOMPARE(list.count(), 3); + QCOMPARE(list.size(), 3); + QCOMPARE(list.size(), 3); QCOMPARE(list.size(), 3); QVERIFY(!list.isEmpty()); list.removeLast(); - QCOMPARE(list.length(), 2); - QCOMPARE(list.count(), 2); + QCOMPARE(list.size(), 2); + QCOMPARE(list.size(), 2); QCOMPARE(list.size(), 2); QVERIFY(!list.isEmpty()); list.removeLast(); - QCOMPARE(list.length(), 1); - QCOMPARE(list.count(), 1); + QCOMPARE(list.size(), 1); + QCOMPARE(list.size(), 1); QCOMPARE(list.size(), 1); QVERIFY(!list.isEmpty()); list.removeLast(); - QCOMPARE(list.length(), 0); - QCOMPARE(list.count(), 0); + QCOMPARE(list.size(), 0); + QCOMPARE(list.size(), 0); QCOMPARE(list.size(), 0); QVERIFY(list.isEmpty()); } @@ -907,7 +1094,6 @@ void tst_QVarLengthArray::count() void tst_QVarLengthArray::cpp17ctad() { -#ifdef __cpp_deduction_guides #define QVERIFY_IS_VLA_OF(obj, Type) \ QVERIFY2((std::is_same<decltype(obj), QVarLengthArray<Type>>::value), \ QMetaType::fromType<decltype(obj)::value_type>().name()) @@ -927,10 +1113,6 @@ void tst_QVarLengthArray::cpp17ctad() CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three")); #undef QVERIFY_IS_VLA_OF #undef CHECK -#else - QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler."); -#endif - } void tst_QVarLengthArray::first() @@ -943,16 +1125,16 @@ void tst_QVarLengthArray::first() QCOMPARE(list.first(), 27); list.append(1987); QCOMPARE(list.first(), 27); - QCOMPARE(list.length(), 3); + QCOMPARE(list.size(), 3); // remove some, make sure it stays sane list.removeLast(); QCOMPARE(list.first(), 27); - QCOMPARE(list.length(), 2); + QCOMPARE(list.size(), 2); list.removeLast(); QCOMPARE(list.first(), 27); - QCOMPARE(list.length(), 1); + QCOMPARE(list.size(), 1); } void tst_QVarLengthArray::last() @@ -965,16 +1147,16 @@ void tst_QVarLengthArray::last() QCOMPARE(list.last(), 4); list.append(1987); QCOMPARE(list.last(), 1987); - QCOMPARE(list.length(), 3); + QCOMPARE(list.size(), 3); // remove some, make sure it stays sane list.removeLast(); QCOMPARE(list.last(), 4); - QCOMPARE(list.length(), 2); + QCOMPARE(list.size(), 2); list.removeLast(); QCOMPARE(list.last(), 27); - QCOMPARE(list.length(), 1); + QCOMPARE(list.size(), 1); } void tst_QVarLengthArray::squeeze() @@ -1018,7 +1200,7 @@ void tst_QVarLengthArray::operators() // +=: not provided, emulate //myvla += myvlatwo; - for (const QString &s : qAsConst(myvlatwo)) + for (const QString &s : std::as_const(myvlatwo)) myvla.push_back(s); QCOMPARE(myvla, combined); @@ -1206,6 +1388,17 @@ void tst_QVarLengthArray::insertMove() QCOMPARE(MyBase::copyCount, 0); { + MyMovable m1, m2; + QCOMPARE(MyBase::liveCount, 2); + QCOMPARE(MyBase::copyCount, 0); + using std::swap; + swap(m1, m2); + QCOMPARE(MyBase::liveCount, 2); + QCOMPARE(MyBase::movedCount, 0); + QCOMPARE(MyBase::copyCount, 0); + } + + { QVarLengthArray<MyMovable, 6> vec; MyMovable m1; MyMovable m2; @@ -1231,7 +1424,7 @@ void tst_QVarLengthArray::insertMove() QCOMPARE(MyBase::liveCount, 6); QCOMPARE(MyBase::movedCount, 2); - vec.prepend(std::move(m1)); + vec.insert(vec.cbegin(), std::move(m1)); QVERIFY(m1.wasConstructedAt(nullptr)); QVERIFY(vec.at(0).wasConstructedAt(&m1)); QVERIFY(vec.at(1).wasConstructedAt(&m3)); @@ -1303,7 +1496,7 @@ void tst_QVarLengthArray::nonCopyable() QVERIFY(!val4); QVERIFY(ptr3 == vec.at(0).get()); QVERIFY(ptr4 == vec.at(1).get()); - vec.prepend(std::move(val1)); + vec.insert(vec.cbegin(), std::move(val1)); QVERIFY(!val1); QVERIFY(ptr1 == vec.at(0).get()); QVERIFY(ptr3 == vec.at(1).get()); @@ -1550,5 +1743,26 @@ void tst_QVarLengthArray::erase() QCOMPARE(arr, QVarLengthArray<QString>({ "val0" })); } +void tst_QVarLengthArray::copesWithCopyabilityOfMoveOnlyVector() +{ + // std::vector<move-only-type> is_copyable + // (https://quuxplusone.github.io/blog/2020/02/05/vector-is-copyable-except-when-its-not/) + + QVarLengthArray<std::vector<std::unique_ptr<int>>, 2> vla; + vla.emplace_back(42); + vla.emplace_back(43); + vla.emplace_back(44); // goes to the heap + QCOMPARE_EQ(vla.size(), 3); + QCOMPARE_EQ(vla.front().size(), 42U); + QCOMPARE_EQ(vla.front().front(), nullptr); + QCOMPARE_EQ(vla.back().size(), 44U); + + auto moved = std::move(vla); + QCOMPARE_EQ(moved.size(), 3); + QCOMPARE_EQ(moved.front().size(), 42U); + QCOMPARE_EQ(moved.front().front(), nullptr); + QCOMPARE_EQ(moved.back().size(), 44U); +} + QTEST_APPLESS_MAIN(tst_QVarLengthArray) #include "tst_qvarlengtharray.moc" |