summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/tools')
-rw-r--r--tests/auto/corelib/tools/CMakeLists.txt58
-rw-r--r--tests/auto/corelib/tools/collections/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/collections/collections.pro8
-rw-r--r--tests/auto/corelib/tools/collections/tst_collections.cpp954
-rw-r--r--tests/auto/corelib/tools/containerapisymmetry/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro6
-rw-r--r--tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp959
-rw-r--r--tests/auto/corelib/tools/qalgorithms/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qalgorithms/qalgorithms.pro4
-rw-r--r--tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp955
-rw-r--r--tests/auto/corelib/tools/qarraydata/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qarraydata/qarraydata.pro5
-rw-r--r--tests/auto/corelib/tools/qarraydata/simplevector.h165
-rw-r--r--tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp1603
-rw-r--r--tests/auto/corelib/tools/qatomicscopedvaluerollback/CMakeLists.txt13
-rw-r--r--tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp164
-rw-r--r--tests/auto/corelib/tools/qbitarray/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qbitarray/qbitarray.pro4
-rw-r--r--tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp464
-rw-r--r--tests/auto/corelib/tools/qcache/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qcache/qcache.pro4
-rw-r--r--tests/auto/corelib/tools/qcache/tst_qcache.cpp166
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/CMakeLists.txt21
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro3
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/CMakeLists.txt12
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp42
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro5
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp165
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro4
-rw-r--r--tests/auto/corelib/tools/qcontiguouscache/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qcontiguouscache/qcontiguouscache.pro4
-rw-r--r--tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp83
-rw-r--r--tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt28
-rw-r--r--tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro11
-rw-r--r--tests/auto/corelib/tools/qcryptographichash/testdata.qrc6
-rw-r--r--tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp441
-rw-r--r--tests/auto/corelib/tools/qduplicatetracker/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp230
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/qeasingcurve.pro4
-rw-r--r--tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp66
-rw-r--r--tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qexplicitlyshareddatapointer/qexplicitlyshareddatapointer.pro4
-rw-r--r--tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp52
-rw-r--r--tests/auto/corelib/tools/qflatmap/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp732
-rw-r--r--tests/auto/corelib/tools/qfreelist/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qfreelist/qfreelist.pro5
-rw-r--r--tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp36
-rw-r--r--tests/auto/corelib/tools/qhash/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qhash/qhash.pro6
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp2068
-rw-r--r--tests/auto/corelib/tools/qhashfunctions/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qhashfunctions/qhashfunctions.pro4
-rw-r--r--tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp480
-rw-r--r--tests/auto/corelib/tools/qhashseed/CMakeLists.txt23
-rw-r--r--tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp186
-rw-r--r--tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp14
-rw-r--r--tests/auto/corelib/tools/qline/CMakeLists.txt25
-rw-r--r--tests/auto/corelib/tools/qline/qline.pro5
-rw-r--r--tests/auto/corelib/tools/qline/tst_qline.cpp205
-rw-r--r--tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro7
-rw-r--r--tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp1072
-rw-r--r--tests/auto/corelib/tools/qlist/.gitignore (renamed from tests/auto/corelib/tools/qvector/.gitignore)0
-rw-r--r--tests/auto/corelib/tools/qlist/CMakeLists.txt22
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp3969
-rw-r--r--tests/auto/corelib/tools/qmacautoreleasepool/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro5
-rw-r--r--tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm54
-rw-r--r--tests/auto/corelib/tools/qmakearray/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qmakearray/qmakearray.pro4
-rw-r--r--tests/auto/corelib/tools/qmakearray/tst_qmakearray.cpp31
-rw-r--r--tests/auto/corelib/tools/qmap/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qmap/qmap.pro6
-rw-r--r--tests/auto/corelib/tools/qmap/tst_qmap.cpp1635
-rw-r--r--tests/auto/corelib/tools/qmargins/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qmargins/qmargins.pro4
-rw-r--r--tests/auto/corelib/tools/qmargins/tst_qmargins.cpp190
-rw-r--r--tests/auto/corelib/tools/qmessageauthenticationcode/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qmessageauthenticationcode/qmessageauthenticationcode.pro5
-rw-r--r--tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp198
-rw-r--r--tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt26
-rw-r--r--tests/auto/corelib/tools/qoffsetstringarray/qoffsetstringarray.pro6
-rw-r--r--tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp72
-rw-r--r--tests/auto/corelib/tools/qpair/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/qpair/qpair.pro7
-rw-r--r--tests/auto/corelib/tools/qpair/tst_qpair.cpp149
-rw-r--r--tests/auto/corelib/tools/qpoint/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qpoint/qpoint.pro4
-rw-r--r--tests/auto/corelib/tools/qpoint/tst_qpoint.cpp147
-rw-r--r--tests/auto/corelib/tools/qpointf/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qpointf/qpointf.pro4
-rw-r--r--tests/auto/corelib/tools/qpointf/tst_qpointf.cpp118
-rw-r--r--tests/auto/corelib/tools/qqueue/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qqueue/qqueue.pro4
-rw-r--r--tests/auto/corelib/tools/qqueue/tst_qqueue.cpp31
-rw-r--r--tests/auto/corelib/tools/qrect/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qrect/qrect.pro4
-rw-r--r--tests/auto/corelib/tools/qrect/tst_qrect.cpp228
-rw-r--r--tests/auto/corelib/tools/qringbuffer/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qringbuffer/qringbuffer.pro4
-rw-r--r--tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp52
-rw-r--r--tests/auto/corelib/tools/qscopedpointer/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro4
-rw-r--r--tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp103
-rw-r--r--tests/auto/corelib/tools/qscopedvaluerollback/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qscopedvaluerollback/qscopedvaluerollback.pro4
-rw-r--r--tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp31
-rw-r--r--tests/auto/corelib/tools/qscopeguard/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/qscopeguard/qscopeguard.pro4
-rw-r--r--tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp161
-rw-r--r--tests/auto/corelib/tools/qset/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qset/qset.pro8
-rw-r--r--tests/auto/corelib/tools/qset/tst_qset.cpp525
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/CMakeLists.txt22
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/externaltests.cpp69
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/externaltests.h29
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/externaltests.pri6
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp31
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h31
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/nontracked.cpp31
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/nontracked.h29
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro17
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp566
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/wrapper.cpp29
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/wrapper.h29
-rw-r--r--tests/auto/corelib/tools/qsize/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qsize/qsize.pro4
-rw-r--r--tests/auto/corelib/tools/qsize/tst_qsize.cpp107
-rw-r--r--tests/auto/corelib/tools/qsizef/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qsizef/qsizef.pro4
-rw-r--r--tests/auto/corelib/tools/qsizef/tst_qsizef.cpp78
-rw-r--r--tests/auto/corelib/tools/qspan/CMakeLists.txt13
-rw-r--r--tests/auto/corelib/tools/qspan/tst_qspan.cpp450
-rw-r--r--tests/auto/corelib/tools/qstl/CMakeLists.txt17
-rw-r--r--tests/auto/corelib/tools/qstl/qstl.pro4
-rw-r--r--tests/auto/corelib/tools/qstl/tst_qstl.cpp35
-rw-r--r--tests/auto/corelib/tools/qtaggedpointer/.gitignore1
-rw-r--r--tests/auto/corelib/tools/qtaggedpointer/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp478
-rw-r--r--tests/auto/corelib/tools/qtimeline/BLACKLIST5
-rw-r--r--tests/auto/corelib/tools/qtimeline/CMakeLists.txt19
-rw-r--r--tests/auto/corelib/tools/qtimeline/qtimeline.pro4
-rw-r--r--tests/auto/corelib/tools/qtimeline/tst_qtimeline.cpp386
-rw-r--r--tests/auto/corelib/tools/qtyperevision/CMakeLists.txt15
-rw-r--r--tests/auto/corelib/tools/qtyperevision/tst_qtyperevision.cpp202
-rw-r--r--tests/auto/corelib/tools/quniquehandle/CMakeLists.txt15
-rw-r--r--tests/auto/corelib/tools/quniquehandle/tst_quniquehandle.cpp308
-rw-r--r--tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro6
-rw-r--r--tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp809
-rw-r--r--tests/auto/corelib/tools/qvector/qvector.pro7
-rw-r--r--tests/auto/corelib/tools/qvector/tst_qvector.cpp2649
-rw-r--r--tests/auto/corelib/tools/qversionnumber/CMakeLists.txt20
-rw-r--r--tests/auto/corelib/tools/qversionnumber/qversionnumber.pro6
-rw-r--r--tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp280
-rw-r--r--tests/auto/corelib/tools/tools.pro43
157 files changed, 18119 insertions, 8735 deletions
diff --git a/tests/auto/corelib/tools/CMakeLists.txt b/tests/auto/corelib/tools/CMakeLists.txt
new file mode 100644
index 0000000000..5cca2e2df6
--- /dev/null
+++ b/tests/auto/corelib/tools/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(qatomicscopedvaluerollback)
+if(NOT INTEGRITY)
+ add_subdirectory(collections)
+endif()
+add_subdirectory(containerapisymmetry)
+add_subdirectory(qalgorithms)
+add_subdirectory(qarraydata)
+add_subdirectory(qbitarray)
+add_subdirectory(qcache)
+add_subdirectory(qcommandlineparser)
+add_subdirectory(qcontiguouscache)
+add_subdirectory(qcryptographichash)
+add_subdirectory(qduplicatetracker)
+add_subdirectory(qeasingcurve)
+add_subdirectory(qexplicitlyshareddatapointer)
+add_subdirectory(qflatmap)
+if(QT_FEATURE_private_tests)
+ add_subdirectory(qfreelist)
+endif()
+add_subdirectory(qhash)
+add_subdirectory(qhashfunctions)
+add_subdirectory(qhashseed)
+add_subdirectory(qline)
+add_subdirectory(qlist)
+add_subdirectory(qmakearray)
+add_subdirectory(qmap)
+add_subdirectory(qmargins)
+add_subdirectory(qmessageauthenticationcode)
+if(NOT INTEGRITY)
+ add_subdirectory(qoffsetstringarray)
+endif()
+add_subdirectory(qpair)
+add_subdirectory(qpoint)
+add_subdirectory(qpointf)
+add_subdirectory(qqueue)
+add_subdirectory(qrect)
+add_subdirectory(qringbuffer)
+add_subdirectory(qscopedpointer)
+add_subdirectory(qscopedvaluerollback)
+add_subdirectory(qscopeguard)
+add_subdirectory(qtaggedpointer)
+add_subdirectory(qtyperevision)
+add_subdirectory(qset)
+add_subdirectory(qsharedpointer)
+add_subdirectory(qsize)
+add_subdirectory(qsizef)
+add_subdirectory(qspan)
+add_subdirectory(qstl)
+add_subdirectory(quniquehandle)
+add_subdirectory(qvarlengtharray)
+add_subdirectory(qversionnumber)
+add_subdirectory(qtimeline)
+if(APPLE)
+ add_subdirectory(qmacautoreleasepool)
+endif()
diff --git a/tests/auto/corelib/tools/collections/CMakeLists.txt b/tests/auto/corelib/tools/collections/CMakeLists.txt
new file mode 100644
index 0000000000..687d88b2e4
--- /dev/null
+++ b/tests/auto/corelib/tools/collections/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_collections Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_collections LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_collections
+ SOURCES
+ tst_collections.cpp
+)
+
+qt_internal_undefine_global_definition(tst_collections QT_NO_JAVA_STYLE_ITERATORS)
diff --git a/tests/auto/corelib/tools/collections/collections.pro b/tests/auto/corelib/tools/collections/collections.pro
deleted file mode 100644
index d5e4e226b5..0000000000
--- a/tests/auto/corelib/tools/collections/collections.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-CONFIG += testcase
-TARGET = tst_collections
-SOURCES += tst_collections.cpp
-QT = core testlib
-
-# This test does not work with strict iterators
-DEFINES -= QT_NO_LINKED_LIST
-DEFINES -= QT_NO_JAVA_STYLE_ITERATORS
diff --git a/tests/auto/corelib/tools/collections/tst_collections.cpp b/tests/auto/corelib/tools/collections/tst_collections.cpp
index 023b22b4ba..2fab6cae3a 100644
--- a/tests/auto/corelib/tools/collections/tst_collections.cpp
+++ b/tests/auto/corelib/tools/collections/tst_collections.cpp
@@ -1,38 +1,13 @@
-/****************************************************************************
-**
-** 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
+#undef QT_NO_FOREACH // this file tests Q_FOREACH over containers (centralize in a tst_qforeach?)
// test the container forwards
#include <QtContainerFwd>
static QCache<int, int> *cacheX;
static QHash<int, int> *hashX;
-static QLinkedList<int> *linkedListX;
static QList<int> *listX;
static QMap<int, int> *mapX;
static QMultiHash<int, int> *multiHashX;
@@ -43,13 +18,12 @@ static QSet<int> *setX;
static QStack<int> *stackX;
static QVarLengthArray<int> *varLengthArrayX;
static QVarLengthArray<int, 512> *varLengthArrayY;
-static QVector<int> *vectorX;
+static QList<int> *vectorX;
void foo()
{
cacheX = 0;
hashX = 0;
- linkedListX = 0;
listX = 0;
mapX = 0;
multiHashX = 0;
@@ -63,7 +37,11 @@ void foo()
vectorX = 0;
}
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QVector>
+#include <QScopedPointer>
+#include <QThread>
+#include <QSemaphore>
#include <algorithm>
@@ -71,7 +49,6 @@ void foo()
#include "qbytearray.h"
#include "qcache.h"
#include "qhash.h"
-#include "qlinkedlist.h"
#include "qlist.h"
#include "qmap.h"
#include "qpair.h"
@@ -81,7 +58,6 @@ void foo()
#include "qstring.h"
#include "qstringlist.h"
#include "qvarlengtharray.h"
-#include "qvector.h"
#include "qqueue.h"
class tst_Collections : public QObject
@@ -92,7 +68,6 @@ private slots:
void typeinfo();
void qstring();
void list();
- void linkedList();
void vector();
void byteArray();
void stack();
@@ -105,7 +80,6 @@ private slots:
#endif
void pair();
void sharableQList();
- void sharableQLinkedList();
void sharableQVector();
void sharableQMap();
void sharableQHash();
@@ -117,8 +91,6 @@ private slots:
void vector_stl();
void list_stl_data();
void list_stl();
- void linkedlist_stl_data();
- void linkedlist_stl();
void q_init();
void pointersize();
void containerInstantiation();
@@ -130,12 +102,27 @@ private slots:
void foreach_2();
void insert_remove_loop();
+
+ void detachAssociativeContainerQMap() { detachAssociativeContainerImpl<QMap>(); }
+ void detachAssociativeContainerQMultiMap() { detachAssociativeContainerImpl<QMultiMap>(); }
+ void detachAssociativeContainerQHash() { detachAssociativeContainerImpl<QHash>(); }
+ void detachAssociativeContainerQMultiHash() { detachAssociativeContainerImpl<QMultiHash>(); }
+
+private:
+ template <template<typename, typename> typename Container>
+ void detachAssociativeContainerImpl();
};
struct LargeStatic {
static int count;
LargeStatic():c(count) { ++count; }
LargeStatic(const LargeStatic& o):c(o.c) { ++count; }
+ LargeStatic &operator=(const LargeStatic &o)
+ {
+ c = o.c;
+ ++count;
+ return *this;
+ };
~LargeStatic() { --count; }
int c;
int data[8];
@@ -153,7 +140,7 @@ struct Movable {
int Movable::count = 0;
QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
@@ -161,10 +148,155 @@ struct Pod {
int i1, i2;
};
+// Compile-time checks for recursive containers
+struct Dummy
+{
+ bool operator==(const Dummy &) const { return false; }
+ bool operator<(const Dummy &) const { return false; }
+};
+
+struct RecursiveList : public QList<RecursiveList> {};
+struct RecursiveSet : public QSet<RecursiveSet> {};
+struct RecursiveMapV : public QMap<Dummy, RecursiveMapV> {};
+struct RecursiveMapK : public QMap<RecursiveMapK, Dummy> {};
+struct RecursiveMultiMapV : public QMultiMap<Dummy, RecursiveMultiMapV> {};
+struct RecursiveMultiMapK : public QMultiMap<RecursiveMultiMapK, Dummy> {};
+struct RecursiveHashV : public QHash<Dummy, RecursiveHashV> {};
+struct RecursiveHashK : public QHash<RecursiveHashK, Dummy> {};
+struct RecursiveMultiHashV : public QMultiHash<Dummy, RecursiveMultiHashV> {};
+struct RecursiveMultiHashK : public QMultiHash<RecursiveMultiHashK, Dummy> {};
+
+struct Empty {};
+struct NoCmpParamRecursiveMapV : public QMap<Empty, NoCmpParamRecursiveMapV> {};
+struct NoCmpParamRecursiveMapK : public QMap<NoCmpParamRecursiveMapK, Empty> {};
+struct NoCmpParamRecursiveMultiMapV : public QMultiMap<Empty, NoCmpParamRecursiveMultiMapV> {};
+struct NoCmpParamRecursiveMultiMapK : public QMultiMap<NoCmpParamRecursiveMultiMapK, Empty> {};
+struct NoCmpParamRecursiveHashV : public QHash<Empty, NoCmpParamRecursiveHashV> {};
+struct NoCmpParamRecursiveHashK : public QHash<NoCmpParamRecursiveHashK, Empty> {};
+struct NoCmpParamRecursiveMultiHashV : public QMultiHash<Empty, NoCmpParamRecursiveMultiHashV> {};
+struct NoCmpParamRecursiveMultiHashK : public QMultiHash<NoCmpParamRecursiveMultiHashK, Empty> {};
+
+struct NoCmpRecursiveList : public QList<NoCmpRecursiveList>
+{
+ bool operator==(const RecursiveList &) const = delete;
+ bool operator<(const RecursiveList &) const = delete;
+};
+struct NoCmpRecursiveSet : public QSet<NoCmpRecursiveSet>
+{
+ bool operator==(const NoCmpRecursiveSet &) const = delete;
+};
+struct NoCmpRecursiveMapV : public QMap<Dummy, NoCmpRecursiveMapV>
+{
+ bool operator==(const NoCmpRecursiveMapV &) const = delete;
+};
+struct NoCmpRecursiveMapK : public QMap<NoCmpRecursiveMapK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMapK &) const = delete;
+};
+struct NoCmpRecursiveMultiMapV : public QMultiMap<Dummy, NoCmpRecursiveMultiMapV>
+{
+ bool operator==(const NoCmpRecursiveMultiMapV &) const = delete;
+};
+struct NoCmpRecursiveMultiMapK : public QMultiMap<NoCmpRecursiveMultiMapK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMultiMapK &) const = delete;
+};
+struct NoCmpRecursiveHashV : public QHash<Dummy, NoCmpRecursiveHashV>
+{
+ bool operator==(const NoCmpRecursiveHashV &) const = delete;
+};
+struct NoCmpRecursiveHashK : public QHash<NoCmpRecursiveHashK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveHashK &) const = delete;
+};
+struct NoCmpRecursiveMultiHashV : public QMultiHash<Dummy, NoCmpRecursiveMultiHashV>
+{
+ bool operator==(const NoCmpRecursiveMultiHashV &) const = delete;
+};
+struct NoCmpRecursiveMultiHashK : public QMultiHash<NoCmpRecursiveMultiHashK, Dummy>
+{
+ bool operator==(const NoCmpRecursiveMultiHashK &) const = delete;
+};
+
+uint qHash(const Dummy &) { return 0; }
+uint qHash(const RecursiveSet &) { return 0; }
+uint qHash(const RecursiveHashK &) { return 0; }
+uint qHash(const RecursiveHashV &) { return 0; }
+uint qHash(const RecursiveMultiHashK &) { return 0; }
+uint qHash(const RecursiveMultiHashV &) { return 0; }
+
+Q_DECLARE_METATYPE(RecursiveList);
+Q_DECLARE_METATYPE(RecursiveSet);
+Q_DECLARE_METATYPE(RecursiveMapV);
+Q_DECLARE_METATYPE(RecursiveMapK);
+Q_DECLARE_METATYPE(RecursiveMultiMapV);
+Q_DECLARE_METATYPE(RecursiveMultiMapK);
+Q_DECLARE_METATYPE(RecursiveHashV);
+Q_DECLARE_METATYPE(RecursiveHashK);
+Q_DECLARE_METATYPE(RecursiveMultiHashV);
+Q_DECLARE_METATYPE(RecursiveMultiHashK);
+
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMapV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMapK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiMapV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiMapK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveHashK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveHashV);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiHashK);
+Q_DECLARE_METATYPE(NoCmpParamRecursiveMultiHashV);
+
+Q_DECLARE_METATYPE(NoCmpRecursiveList);
+Q_DECLARE_METATYPE(NoCmpRecursiveMapV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMapK);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiMapV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiMapK);
+Q_DECLARE_METATYPE(NoCmpRecursiveHashV);
+Q_DECLARE_METATYPE(NoCmpRecursiveHashK);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiHashV);
+Q_DECLARE_METATYPE(NoCmpRecursiveMultiHashK);
+
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveList>);
+static_assert(QTypeTraits::has_operator_less_than_v<RecursiveList>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveSet>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMapV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMapK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiMapV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiMapK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveHashV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveHashK>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiHashV>);
+static_assert(QTypeTraits::has_operator_equal_v<RecursiveMultiHashK>);
+
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveHashK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpParamRecursiveMultiHashK>);
+
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveList>);
+static_assert(!QTypeTraits::has_operator_less_than_v<NoCmpRecursiveList>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveSet>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiMapV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiMapK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveHashK>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiHashV>);
+static_assert(!QTypeTraits::has_operator_equal_v<NoCmpRecursiveMultiHashK>);
+
+template <typename T>
+constexpr inline bool has_prepend_v = true;
+template <typename T, qsizetype N>
+constexpr inline bool has_prepend_v<QVarLengthArray<T,N>> = false; // deprecated in Qt 6.3
+
void tst_Collections::typeinfo()
{
- QVERIFY(QTypeInfo<int*>::isPointer);
- QVERIFY(!QTypeInfo<int>::isPointer);
+ QVERIFY(std::is_pointer_v<int*>);
+ QVERIFY(!std::is_pointer_v<int>);
QVERIFY(QTypeInfo<QString>::isComplex);
QVERIFY(!QTypeInfo<int>::isComplex);
}
@@ -398,7 +530,7 @@ void tst_Collections::list()
list << "one" << "two" << "one" << "two";
QVERIFY(!list.removeOne("three"));
QVERIFY(list.removeOne("two"));
- QCOMPARE(list, QList<QString>() << "one" << "one" << "two");;
+ QCOMPARE(list, QList<QString>() << "one" << "one" << "two");
QVERIFY(list.removeOne("two"));
QCOMPARE(list, QList<QString>() << "one" << "one");
QVERIFY(!list.removeOne("two"));
@@ -457,7 +589,10 @@ void tst_Collections::list()
{
QList<int> list;
list.append(1);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
list = list;
+QT_WARNING_POP
QVERIFY(list.size() == 1);
}
}
@@ -471,7 +606,7 @@ void tst_Collections::list()
}
{
- QVector<QString> vector(5);
+ QList<QString> vector(5);
vector[0] = "99";
vector[4] ="100";
QList<QString> list = vector.toList();
@@ -550,7 +685,7 @@ void tst_Collections::list()
list.insert(0, "atzero");
QCOMPARE(list.at(0), QString("atzero"));
- int listCount = list.count();
+ int listCount = list.size();
list.insert(listCount, "atcount");
QCOMPARE(list.at(listCount), QString("atcount"));
}
@@ -725,231 +860,9 @@ void tst_Collections::list()
}
}
-void tst_Collections::linkedList()
-{
- {
- QLinkedList<int> list;
- QVERIFY(list.isEmpty());
- list.append(1);
- list.push_back(2);
- list += (3);
- list << 4 << 5 << 6;
- QVERIFY(!list.isEmpty());
- QVERIFY(list.size() == 6);
- {
- int sum = 0;
- QLinkedListIterator<int> i = list;
- while (i.hasNext()) {
- sum += i.next();
- }
- QVERIFY(sum == 21);
- }
- {
- int sum = 0;
- QLinkedList<int>::const_iterator i = list.begin();
- while (i != list.end())
- sum += *i++;
- QVERIFY(sum == 21);
- }
- {
- QMutableLinkedListIterator<int> i = list;
- while (i.hasNext())
- i.setValue(2*i.next());
- }
- {
- int sum = 0;
- QLinkedListIterator<int> i = list;
- i.toBack();
- while (i.hasPrevious())
- sum += i.previous();
- QVERIFY(sum == 2*21);
- }
- {
- QMutableLinkedListIterator<int> i = list;
- i.toBack();
- while (i.hasPrevious())
- i.setValue(2*i.previous());
- }
- {
- int sum = 0;
- QLinkedListIterator<int> i = list;
- i.toBack();
- while (i.hasPrevious())
- sum += i.previous();
- QVERIFY(sum == 2*2*21);
- }
- {
- QMutableLinkedListIterator<int> i = list;
- while (i.hasNext()) {
- int a = i.next();
- i.insert(a);
- }
- }
- {
- int sum = 0;
- QLinkedList<int>::iterator i = list.begin();
- while (i != list.end())
- sum += *i++;
- QVERIFY(sum == 2*2*2*21);
- }
- {
- int duplicates = 0;
- QLinkedListIterator<int> i = list;
- while (i.hasNext()) {
- int a = i.next();
- if (i.hasNext() && a == i.peekNext())
- duplicates++;
- }
- QVERIFY(duplicates == 6);
- }
- {
- int duplicates = 0;
- QLinkedListIterator<int> i = list;
- i.toBack();
- while (i.hasPrevious()) {
- int a = i.previous();
- if (i.hasPrevious() && a == i.peekPrevious())
- duplicates++;
- }
- QVERIFY(duplicates == 6);
- }
- {
- QMutableLinkedListIterator<int> i = list;
- while (i.hasNext()) {
- int a = i.next();
- if (i.hasNext() &&
- i.peekNext() == a)
- i.remove();
- }
- }
- {
- int duplicates = 0;
- QMutableLinkedListIterator<int> i = list;
- i.toBack();
- while (i.hasPrevious()) {
- int a = i.previous();
- if (i.hasPrevious() && a == i.peekPrevious())
- duplicates++;
- }
- QVERIFY(duplicates == 0);
- }
- {
- QVERIFY(list.size() == 6);
- QMutableLinkedListIterator<int> i = list;
- while (i.hasNext()) {
- int a = i.peekNext();
- i.insert(42);
- QVERIFY(i.peekPrevious() == 42 && i.peekNext() == a);
- i.next();
- }
- QVERIFY(list.size() == 12);
- i.toFront();
- while (i.findNext(42))
- i.remove();
- }
- {
- QLinkedList<int> l;
- l << 4 << 8 << 12 << 16 << 20 << 24;
- QVERIFY(l == list);
- QLinkedList<int> copy = list;
- list += list;
- QVERIFY(l != list && l.size() == list.size()/2 && l == copy);
- l += copy;
- QVERIFY(l == list);
- list = copy;
- }
- {
- QLinkedList<int> copy = list;
- list.prepend(999);
- list.append(999);
- QVERIFY(list.contains(999));
- QVERIFY(list.count(999) == 2);
- list.removeAll(999);
- QVERIFY(list == copy);
- }
- {
- QLinkedList<QString> list;
- list << "one" << "two" << "three" << "four" << "five" << "six";
- while (!list.isEmpty())
- list.removeAll(list.first());
- }
- {
- QLinkedList<QString> list;
- list << "one" << "two" << "one" << "two";
- QVERIFY(!list.removeOne("three"));
- QVERIFY(list.removeOne("two"));
- QCOMPARE(list, QLinkedList<QString>() << "one" << "one" << "two");;
- QVERIFY(list.removeOne("two"));
- QCOMPARE(list, QLinkedList<QString>() << "one" << "one");
- QVERIFY(!list.removeOne("two"));
- QCOMPARE(list, QLinkedList<QString>() << "one" << "one");
- QVERIFY(list.removeOne("one"));
- QCOMPARE(list, QLinkedList<QString>() << "one");
- QVERIFY(list.removeOne("one"));
- QVERIFY(list.isEmpty());
- QVERIFY(!list.removeOne("one"));
- QVERIFY(list.isEmpty());
- }
- {
- list.clear();
- QVERIFY(list.isEmpty());
- QVERIFY(list.begin() == list.end());
- QLinkedListIterator<int> i(list);
- QVERIFY(!i.hasNext() && !i.hasPrevious());
- }
- }
-
- {
- QLinkedList<QString> list;
- list.append("Hello");
-
- QLinkedList<QString>::iterator it = list.begin();
- QVERIFY((*it)[0] == QChar('H'));
- QVERIFY(it->constData()[0] == QChar('H'));
- it->replace(QChar('H'), QChar('X'));
- QCOMPARE(list.first(), QLatin1String("Xello"));
-
- QLinkedList<QString>::const_iterator cit = list.constBegin();
- QCOMPARE((*cit).toLower(), QLatin1String("xello"));
- QCOMPARE(cit->toUpper(), QLatin1String("XELLO"));
-
- cit = list.cbegin();
- QCOMPARE((*cit).toLower(), QLatin1String("xello"));
- QCOMPARE(cit->toUpper(), QLatin1String("XELLO"));
- }
-
- {
- QLinkedList<QString> list;
- list << "alpha" << "beta";
- list += list;
- QVERIFY(list.size() == 4);
- QCOMPARE(*list.begin(), QLatin1String("alpha"));
- QCOMPARE(*(list.begin() + 1), QLatin1String("beta"));
- QCOMPARE(*(list.begin() + 2), QLatin1String("alpha"));
- QCOMPARE(*(list.begin() + 3), QLatin1String("beta"));
- }
-
- {
- QLinkedList<int> a;
- QCOMPARE(a.startsWith(1), false);
- QCOMPARE(a.endsWith(1), false);
- a.append(1);
- QCOMPARE(a.startsWith(1), true);
- QCOMPARE(a.startsWith(2), false);
- QCOMPARE(a.endsWith(1), true);
- QCOMPARE(a.endsWith(2), false);
- a.append(2);
- QCOMPARE(a.startsWith(1), true);
- QCOMPARE(a.startsWith(2), false);
- QCOMPARE(a.endsWith(1), false);
- QCOMPARE(a.endsWith(2), true);
- }
-};
-
-
void tst_Collections::vector()
{
- QVector<int> v1;
+ QList<int> v1;
v1 << 1 << 2 << 3;
QVector<int> v2;
v2 << 4 << 5;
@@ -1033,7 +946,7 @@ void tst_Collections::vector()
QVERIFY(LargeStatic::count == originalLargeStaticCount);
{
QVector<LargeStatic> vector;
- LargeStatic *dummy = 0;
+ LargeStatic *dummy = nullptr;
for (int i = 0; i < 10000; ++i) {
delete dummy;
dummy = new LargeStatic;
@@ -1055,7 +968,7 @@ void tst_Collections::vector()
QVERIFY(Movable::count == originalMovableCount);
{
QVector<Movable> vector;
- Movable *dummy = 0;
+ Movable *dummy = nullptr;
for (int i = 0; i < 10000; ++i) {
delete dummy;
dummy = new Movable;
@@ -1198,6 +1111,16 @@ void tst_Collections::byteArray()
QVERIFY(hello.indexOf('l',2) == 2);
QVERIFY(hello.indexOf('l',3) == 3);
+ QByteArray empty;
+ QCOMPARE(empty.indexOf("x"), -1);
+ QCOMPARE(empty.lastIndexOf("x"), -1);
+ QCOMPARE(empty.lastIndexOf("x", 0), -1);
+ QCOMPARE(empty.count("x"), 0);
+ QCOMPARE(empty.indexOf(""), 0);
+ QCOMPARE(empty.lastIndexOf(""), 0);
+ QCOMPARE(empty.lastIndexOf("", -1), -1);
+ QCOMPARE(empty.count(""), 1);
+
QByteArray large = "000 100 200 300 400 500 600 700 800 900";
QVERIFY(large.indexOf("700") == 28);
@@ -1313,7 +1236,7 @@ void tst_Collections::stack()
stack.push(1);
stack.push(2);
stack.push(3);
- QVectorIterator<int> i = stack;
+ QListIterator<int> i = stack;
i.toBack();
int sum = 0;
while (i.hasPrevious())
@@ -1342,17 +1265,17 @@ void tst_Collections::hash()
Hash hash;
QString key = QLatin1String(" ");
for (int i = 0; i < 10; ++i) {
- key[0] = i + '0';
+ key[0] = QChar(i + '0');
for (int j = 0; j < 10; ++j) {
- key[1] = j + '0';
+ key[1] = QChar(j + '0');
hash.insert(key, "V" + key);
}
}
for (int i = 0; i < 10; ++i) {
- key[0] = i + '0';
+ key[0] = QChar(i + '0');
for (int j = 0; j < 10; ++j) {
- key[1] = j + '0';
+ key[1] = QChar(j + '0');
hash.remove(key);
}
}
@@ -1367,6 +1290,8 @@ void tst_Collections::hash()
QVERIFY(hash.size() == 2);
QVERIFY(!hash.isEmpty());
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
{
Hash hash2 = hash;
hash2 = hash;
@@ -1379,6 +1304,7 @@ void tst_Collections::hash()
QVERIFY(hash2.isEmpty());
}
QVERIFY(hash.size() == 2);
+QT_WARNING_POP
{
Hash hash2 = hash;
@@ -1515,19 +1441,13 @@ void tst_Collections::hash()
QHash<int, int> hash;
for (int i = 0; i < 1000; ++i)
hash.insert(i, i);
- QVERIFY(hash.capacity() == 1031);
- hash.squeeze();
- QVERIFY(hash.capacity() == 521);
-
- hash.insert(12345, 12345);
- QVERIFY(hash.capacity() == 1031);
+ QVERIFY(hash.capacity() > 1000);
for (int j = 0; j < 900; ++j)
hash.remove(j);
- QVERIFY(hash.capacity() == 257);
+ QVERIFY(hash.capacity() > 1000);
hash.squeeze();
- QVERIFY(hash.capacity() == 67);
- hash.reserve(0);
+ QVERIFY(hash.capacity() < 200);
}
}
@@ -1551,22 +1471,30 @@ void tst_Collections::hash()
}
{
- QHash<int, QString> hash1, hash2;
- hash1.insertMulti(1, "Alpha");
- hash1.insertMulti(1, "Gamma");
- hash2.insertMulti(1, "Beta");
- hash2.insertMulti(1, "Gamma");
- hash2.insertMulti(1, "Gamma");
+ QMultiHash<int, QString> hash1, hash2;
+ hash1.insert(1, "Alpha");
+ hash1.insert(1, "Gamma");
+ hash2.insert(1, "Beta");
+ hash2.insert(1, "Gamma");
+ hash2.insert(1, "Gamma");
hash1.unite(hash2);
QCOMPARE(hash1.size(), 5);
- QCOMPARE(hash1.values(),
- (QList<QString>() << "Gamma" << "Gamma" << "Beta" << "Gamma" << "Alpha"));
+ auto values = hash1.values();
+ std::sort(values.begin(), values.end());
+ QList<QString> expected;
+ expected << "Gamma" << "Gamma" << "Beta" << "Gamma" << "Alpha";
+ std::sort(expected.begin(), expected.end());
+ QCOMPARE(values, expected);
hash2 = hash1;
hash2.unite(hash2);
QCOMPARE(hash2.size(), 10);
- QCOMPARE(hash2.values(), hash1.values() + hash1.values());
+ values = hash2.values();
+ std::sort(values.begin(), values.end());
+ expected += expected;
+ std::sort(expected.begin(), expected.end());
+ QCOMPARE(values, expected);
}
}
@@ -1588,6 +1516,8 @@ void tst_Collections::map()
QVERIFY(map.size() == 2);
QVERIFY(!map.isEmpty());
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
{
Map map2 = map;
map2 = map;
@@ -1600,6 +1530,7 @@ void tst_Collections::map()
QVERIFY(map2.isEmpty());
}
QVERIFY(map.size() == 2);
+QT_WARNING_POP
{
Map map2 = map;
@@ -1872,12 +1803,12 @@ void tst_Collections::map()
}
{
- QMap<int, QString> map1, map2;
- map1.insertMulti(1, "Alpha");
- map1.insertMulti(1, "Gamma");
- map2.insertMulti(1, "Beta");
- map2.insertMulti(1, "Gamma");
- map2.insertMulti(1, "Gamma");
+ QMultiMap<int, QString> map1, map2;
+ map1.insert(1, "Alpha");
+ map1.insert(1, "Gamma");
+ map2.insert(1, "Beta");
+ map2.insert(1, "Gamma");
+ map2.insert(1, "Gamma");
map1.unite(map2);
QCOMPARE(map1.size(), 5);
@@ -1922,11 +1853,21 @@ void tst_Collections::qstring()
QVERIFY (hello.contains('e') != false);
QVERIFY(hello.indexOf('e') == 1);
- QVERIFY(hello.indexOf('e', -10) == 1);
+ QVERIFY(hello.indexOf('e', -10) == -1);
QVERIFY(hello.indexOf('l') == 2);
QVERIFY(hello.indexOf('l',2) == 2);
QVERIFY(hello.indexOf('l',3) == 3);
+ QString empty;
+ QCOMPARE(empty.indexOf("x"), -1);
+ QCOMPARE(empty.lastIndexOf("x"), -1);
+ QCOMPARE(empty.lastIndexOf("x", 0), -1);
+ QCOMPARE(empty.count("x"), 0);
+ QCOMPARE(empty.indexOf(""), 0);
+ QCOMPARE(empty.lastIndexOf(""), 0);
+ QCOMPARE(empty.lastIndexOf("", -1), -1);
+ QCOMPARE(empty.count(""), 1);
+
QString large = "000 100 200 300 400 500 600 700 800 900";
QVERIFY(large.indexOf("700") == 28);
@@ -1936,6 +1877,20 @@ void tst_Collections::qstring()
QVERIFY(large.lastIndexOf("700", 28) == 28);
QVERIFY(large.lastIndexOf("700", 27) == -1);
+ QCOMPARE(large.indexOf(""), 0);
+ QCOMPARE(large.indexOf(QString()), 0);
+ QCOMPARE(large.indexOf(QLatin1String()), 0);
+ QCOMPARE(large.indexOf(QStringView()), 0);
+ QCOMPARE(large.lastIndexOf(""), large.size());
+ QCOMPARE(large.lastIndexOf("", -1), large.size() - 1);
+ QCOMPARE(large.lastIndexOf(QString()), large.size());
+ QCOMPARE(large.lastIndexOf(QLatin1String()), large.size());
+ QCOMPARE(large.lastIndexOf(QStringView()), large.size());
+ QCOMPARE(large.count(""), large.size() + 1);
+ QCOMPARE(large.count(QString()), large.size() + 1);
+ QCOMPARE(large.count(QLatin1String()), large.size() + 1);
+ QCOMPARE(large.count(QStringView()), large.size() + 1);
+
QVERIFY(large.contains("200"));
QVERIFY(!large.contains("201"));
QVERIFY(large.contains('3'));
@@ -1986,15 +1941,6 @@ void tst_Collections::qstring()
QVERIFY(null.isNull());
QVERIFY(!nonNull.isNull());
-#if QT_DEPRECATED_SINCE(5, 9)
- QVERIFY(null == QString::null);
- QVERIFY(QString::null == null);
- QVERIFY(nonNull != QString::null);
- QVERIFY(QString::null != nonNull);
- QVERIFY(null == nonNull);
- QVERIFY(QString::null == QString::null);
-#endif
-
QString fill = "123";
fill.fill('a');
QCOMPARE(fill, QLatin1String("aaa"));
@@ -2073,8 +2019,8 @@ void tst_Collections::qstring()
s = "ascii";
s += QChar((uchar) 0xb0);
QVERIFY(s.toUtf8() != s.toLatin1());
- QCOMPARE(s[s.length()-1].unicode(), (ushort)0xb0);
- QCOMPARE(s.left(s.length()-1), QLatin1String("ascii"));
+ QCOMPARE(s[s.size()-1].unicode(), char16_t(0xb0));
+ QCOMPARE(s.left(s.size()-1), QLatin1String("ascii"));
QVERIFY(s == QString::fromUtf8(s.toUtf8().constData()));
@@ -2126,7 +2072,7 @@ void tst_Collections::qstring()
QString str = "Hello";
- QString cstr = QString::fromRawData(str.unicode(), str.length());
+ QString cstr = QString::fromRawData(str.unicode(), str.size());
QCOMPARE(str, QLatin1String("Hello"));
QCOMPARE(cstr, QLatin1String("Hello"));
cstr.clear();
@@ -2320,12 +2266,6 @@ void populate(QList<int> &container)
}
template <>
-void populate(QLinkedList<int> &container)
-{
- container << 1 << 2 << 4 << 8;
-}
-
-template <>
void populate(QMap<int, int> &container)
{
container.insert(1, 1);
@@ -2414,11 +2354,6 @@ void tst_Collections::sharableQList()
TEST_SEQUENTIAL_CONTAINER(List);
}
-void tst_Collections::sharableQLinkedList()
-{
- TEST_SEQUENTIAL_CONTAINER(LinkedList);
-}
-
void tst_Collections::sharableQVector()
{
TEST_SEQUENTIAL_CONTAINER(Vector);
@@ -2594,7 +2529,7 @@ template <class Container>
void testLinkedListLikeStlIterators()
{
Container fake;
- typename Container::value_type t;
+ typename Container::value_type t = {};
fake << t;
typename Container::iterator i1 = fake.begin(), i2 = i1 + 1;
@@ -2627,7 +2562,7 @@ void testListLikeStlIterators()
testLinkedListLikeStlIterators<Container>();
Container fake;
- typename Container::value_type t;
+ typename Container::value_type t = {};
fake << t;
typename Container::iterator i1 = fake.begin(), i2 = i1 + 1;
@@ -2710,8 +2645,10 @@ void testMapLikeStlIterators()
QString t;
fake.insert(k, t);
- typename Container::iterator i1 = fake.begin(), i2 = i1 + 1;
- typename Container::const_iterator c1 = i1, c2 = c1 + 1;
+ typename Container::iterator i1 = fake.begin(), i2 = i1;
+ ++i2;
+ typename Container::const_iterator c1 = i1, c2 = c1;
+ ++c2;
QVERIFY(i1 == i1);
QVERIFY(i1 == c1);
@@ -2721,8 +2658,6 @@ void testMapLikeStlIterators()
QVERIFY(i2 == c2);
QVERIFY(c2 == i2);
QVERIFY(c2 == c2);
- QVERIFY(1 + i1 == i1 + 1);
- QVERIFY(1 + c1 == c1 + 1);
QVERIFY(i1 != i2);
QVERIFY(i1 != c2);
@@ -2736,14 +2671,12 @@ void testMapLikeStlIterators()
void tst_Collections::constAndNonConstStlIterators()
{
- testListLikeStlIterators<QList<int> >();
- testListLikeStlIterators<QStringList >();
- testLinkedListLikeStlIterators<QLinkedList<int> >();
- testListLikeStlIterators<QVector<int> >();
- testMapLikeStlIterators<QMap<QString, QString> >();
- testMapLikeStlIterators<QMultiMap<QString, QString> >();
- testMapLikeStlIterators<QHash<QString, QString> >();
- testMapLikeStlIterators<QMultiHash<QString, QString> >();
+ testListLikeStlIterators<QList<int>>();
+ testListLikeStlIterators<QStringList>();
+ testMapLikeStlIterators<QMap<QString, QString>>();
+ testMapLikeStlIterators<QMultiMap<QString, QString>>();
+ testMapLikeStlIterators<QHash<QString, QString>>();
+ testMapLikeStlIterators<QMultiHash<QString, QString>>();
}
void tst_Collections::vector_stl_data()
@@ -2760,8 +2693,8 @@ void tst_Collections::vector_stl()
{
QFETCH(QStringList, elements);
- QVector<QString> vector;
- for (int i = 0; i < elements.count(); ++i)
+ QList<QString> vector;
+ for (int i = 0; i < elements.size(); ++i)
vector << elements.at(i);
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
@@ -2776,34 +2709,9 @@ void tst_Collections::vector_stl()
QCOMPARE(*it, vector[j]);
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- QCOMPARE(QVector<QString>::fromStdVector(stdVector), vector);
+ QCOMPARE(QList<QString>::fromStdVector(stdVector), vector);
#endif
- QCOMPARE(QVector<QString>(stdVector.begin(), stdVector.end()), vector);
-}
-
-void tst_Collections::linkedlist_stl_data()
-{
- list_stl_data();
-}
-
-void tst_Collections::linkedlist_stl()
-{
- QFETCH(QStringList, elements);
-
- QLinkedList<QString> list;
- for (int i = 0; i < elements.count(); ++i)
- list << elements.at(i);
-
- std::list<QString> stdList = list.toStdList();
-
- QCOMPARE(int(stdList.size()), elements.size());
-
- std::list<QString>::const_iterator it = stdList.begin();
- QLinkedList<QString>::const_iterator it2 = list.cbegin();
- for (uint j = 0; j < stdList.size(); ++j, ++it, ++it2)
- QCOMPARE(*it, *it2);
-
- QCOMPARE(QLinkedList<QString>::fromStdList(stdList), list);
+ QCOMPARE(QList<QString>(stdVector.begin(), stdVector.end()), vector);
}
void tst_Collections::list_stl_data()
@@ -2821,7 +2729,7 @@ void tst_Collections::list_stl()
QFETCH(QStringList, elements);
QList<QString> list;
- for (int i = 0; i < elements.count(); ++i)
+ for (int i = 0; i < elements.size(); ++i)
list << elements.at(i);
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
@@ -2843,7 +2751,7 @@ void tst_Collections::list_stl()
}
template <typename T>
-T qtInit(T * = 0)
+T qtInit(T * = nullptr)
{
return T();
}
@@ -2853,9 +2761,9 @@ void tst_Collections::q_init()
QCOMPARE(qtInit<int>(), 0);
QCOMPARE(qtInit<double>(), 0.0);
QCOMPARE(qtInit<QString>(), QString());
- QCOMPARE(qtInit<int *>(), static_cast<int *>(0));
- QCOMPARE(qtInit<double *>(), static_cast<double *>(0));
- QCOMPARE(qtInit<QString *>(), static_cast<QString *>(0));
+ QCOMPARE(qtInit<int *>(), static_cast<int *>(nullptr));
+ QCOMPARE(qtInit<double *>(), static_cast<double *>(nullptr));
+ QCOMPARE(qtInit<QString *>(), static_cast<QString *>(nullptr));
QCOMPARE(qtInit<Pod>().i1, 0);
QCOMPARE(qtInit<Pod>().i2, 0);
}
@@ -2869,6 +2777,7 @@ class LessThanComparable
{
public:
bool operator<(const LessThanComparable &) const { return true; }
+ bool operator==(const LessThanComparable &) const { return true; }
};
class EqualsComparable
@@ -2877,7 +2786,7 @@ public:
bool operator==(const EqualsComparable &) const { return true; }
};
-uint qHash(const EqualsComparable &)
+size_t qHash(const EqualsComparable &)
{
return 0;
}
@@ -2909,11 +2818,11 @@ void instantiateContainer()
constIt = constContainer.end();
constIt = constContainer.cend();
container.constEnd();
- Q_UNUSED(constIt)
+ Q_UNUSED(constIt);
container.clear();
container.contains(value);
- container.count();
+ container.size();
container.empty();
container.isEmpty();
container.size();
@@ -2932,11 +2841,7 @@ void instantiateMutableIterationContainer()
typename ContainerType::iterator it;
it = container.begin();
it = container.end();
- Q_UNUSED(it)
-
- // QSet lacks count(T).
- const ValueType value = ValueType();
- container.count(value);
+ Q_UNUSED(it);
}
template <typename ContainerType, typename ValueType>
@@ -2944,10 +2849,9 @@ void instantiateSequence()
{
instantiateMutableIterationContainer<ContainerType, ValueType>();
-// QVector lacks removeAll(T)
-// ValueType value = ValueType();
-// ContainerType container;
-// container.removeAll(value);
+ ValueType value = ValueType();
+ ContainerType container;
+ container.removeAll(value);
}
template <typename ContainerType, typename ValueType>
@@ -3002,14 +2906,12 @@ void instantiatePairAssociative()
{
instantiateMutableIterationContainer<ContainerType, KeyType>();
- typename ContainerType::iterator it;
- typename ContainerType::const_iterator constIt;
const KeyType key = KeyType();
const ValueType value = ValueType();
ContainerType container;
const ContainerType constContainer(container);
- it = container.insert(key, value);
+ auto it = container.insert(key, value);
container.erase(it);
container.find(key);
container.constFind(key);
@@ -3020,11 +2922,10 @@ void instantiatePairAssociative()
constContainer.keys();
container.remove(key);
container.take(key);
- container.unite(constContainer);
+ container.insert(constContainer);
container.value(key);
container.value(key, value);
container.values();
- container.values(key);
container[key];
const int foo = constContainer[key];
Q_UNUSED(foo);
@@ -3053,15 +2954,6 @@ void tst_Collections::containerInstantiation()
typedef QSet<EqualsComparable> Set;
instantiateAssociative<Set, EqualsComparable>();
- //Instantiate QLinkedList member functions.
- typedef QLinkedList<EqualsComparable> LinkedList;
- instantiateSequence<LinkedList, EqualsComparable> ();
- {
- EqualsComparable value;
- LinkedList list;
- list.removeAll(value);
- }
-
//Instantiate QList member functions.
typedef QList<EqualsComparable> List;
instantiateRandomAccess<List, EqualsComparable>();
@@ -3071,10 +2963,6 @@ void tst_Collections::containerInstantiation()
list.removeAll(value);
}
- //Instantiate QVector member functions.
- typedef QVector<EqualsComparable> Vector;
- instantiateRandomAccess<Vector, EqualsComparable>();
-
//Instantiate QQueue member functions.
typedef QQueue<EqualsComparable> Queue;
instantiateRandomAccess<Queue, EqualsComparable>();
@@ -3112,7 +3000,7 @@ void tst_Collections::qtimerList()
template <typename Container>
void testContainerTypedefs(Container container)
{
- Q_UNUSED(container)
+ Q_UNUSED(container);
{ QVERIFY_TYPE(typename Container::value_type); }
{ QVERIFY_TYPE(typename Container::iterator); }
{ QVERIFY_TYPE(typename Container::const_iterator); }
@@ -3126,7 +3014,7 @@ void testContainerTypedefs(Container container)
template <typename Container>
void testPairAssociativeContainerTypedefs(Container container)
{
- Q_UNUSED(container)
+ Q_UNUSED(container);
// TODO: Not sure how to define value_type for our associative containers
// { QVERIFY_TYPE(typename Container::value_type); }
@@ -3148,7 +3036,7 @@ void testPairAssociativeContainerTypedefs(Container container)
template <typename Container>
void testSetContainerTypedefs(Container container)
{
- Q_UNUSED(container)
+ Q_UNUSED(container);
{ QVERIFY_TYPE(typename Container::iterator); }
{ QVERIFY_TYPE(typename Container::const_iterator); }
{ QVERIFY_TYPE(typename Container::reference); }
@@ -3165,10 +3053,8 @@ void testSetContainerTypedefs(Container container)
*/
void tst_Collections::containerTypedefs()
{
- testContainerTypedefs(QVector<int>());
testContainerTypedefs(QStack<int>());
testContainerTypedefs(QList<int>());
- testContainerTypedefs(QLinkedList<int>());
testContainerTypedefs(QQueue<int>());
testPairAssociativeContainerTypedefs(QMap<int, int>());
@@ -3184,32 +3070,40 @@ class T2;
void tst_Collections::forwardDeclared()
{
- { typedef QHash<Key1, T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QMultiHash<Key1, T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QMap<Key1, T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QMultiMap<Key1, T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QPair<T1, T2> C; C *x = 0; Q_UNUSED(x) }
- { typedef QList<T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QLinkedList<T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QVector<T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) Q_UNUSED(i) Q_UNUSED(j) }
- { typedef QStack<T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) Q_UNUSED(i) Q_UNUSED(j) }
- { typedef QQueue<T1> C; C *x = 0; C::iterator i; C::const_iterator j; Q_UNUSED(x) }
- { typedef QSet<T1> C; C *x = 0; /* C::iterator i; */ C::const_iterator j; Q_UNUSED(x) }
-}
+#define TEST(...) do { \
+ using C = __VA_ARGS__; \
+ C *x = nullptr; \
+ C::iterator i; \
+ C::const_iterator j; \
+ Q_UNUSED(x); \
+ Q_UNUSED(i); \
+ Q_UNUSED(j); \
+ } while (false)
+
+ TEST(QHash<Key1, T1>);
+ TEST(QMap<Key1, T1>);
+ TEST(QMultiMap<Key1, T1>);
+ TEST(QList<T1>);
+ TEST(QVector<T1>);
+ TEST(QStack<T1>);
+ TEST(QQueue<T1>);
+ TEST(QSet<T1>);
+#undef TEST
-class alignas(4) Aligned4
-{
- char i;
-public:
- Aligned4(int i = 0) : i(i) {}
-
- enum { PreferredAlignment = 4 };
+ {
+ using C = QPair<T1, T2>;
+ C *x = nullptr;
+ Q_UNUSED(x);
+ }
- inline bool operator==(const Aligned4 &other) const { return i == other.i; }
- inline bool operator<(const Aligned4 &other) const { return i < other.i; }
- friend inline int qHash(const Aligned4 &a) { return qHash(a.i); }
-};
-Q_STATIC_ASSERT(alignof(Aligned4) % 4 == 0);
+ {
+ using C = QSet<T1>;
+ C *x = nullptr;
+ C::const_iterator j;
+ Q_UNUSED(x);
+ Q_UNUSED(j);
+ }
+}
#if defined(Q_PROCESSOR_ARM)
# if defined(Q_COMPILER_ALIGNAS) && defined(__BIGGEST_ALIGNMENT__)
@@ -3223,19 +3117,30 @@ Q_STATIC_ASSERT(alignof(Aligned4) % 4 == 0);
# define BIGGEST_ALIGNMENT_TO_TEST 128
#endif
-class alignas(BIGGEST_ALIGNMENT_TO_TEST) AlignedBiggest
+template <size_t Alignment>
+class alignas(Alignment) AlignedClass
{
char i;
+
public:
- AlignedBiggest(int i = 0) : i(i) {}
+ AlignedClass(int i = 0) : i(i) {}
- enum { PreferredAlignment = BIGGEST_ALIGNMENT_TO_TEST };
+ enum { PreferredAlignment = Alignment };
- inline bool operator==(const AlignedBiggest &other) const { return i == other.i; }
- inline bool operator<(const AlignedBiggest &other) const { return i < other.i; }
- friend inline int qHash(const AlignedBiggest &a) { return qHash(a.i); }
+ inline bool operator==(const AlignedClass &other) const { return i == other.i; }
+ inline bool operator<(const AlignedClass &other) const { return i < other.i; }
+ friend inline size_t qHash(const AlignedClass &a) { return qHash(a.i); }
};
-Q_STATIC_ASSERT(alignof(AlignedBiggest) % BIGGEST_ALIGNMENT_TO_TEST == 0);
+
+using Aligned4 = AlignedClass<4>;
+static_assert(alignof(Aligned4) % 4 == 0);
+
+using AlignedStdMax = AlignedClass<alignof(std::max_align_t)>;
+static_assert(alignof(AlignedStdMax) % alignof(std::max_align_t) == 0);
+
+using AlignedBiggest = AlignedClass<BIGGEST_ALIGNMENT_TO_TEST>;
+static_assert(BIGGEST_ALIGNMENT_TO_TEST > alignof(std::max_align_t), "Not overly aligned");
+static_assert(alignof(AlignedBiggest) % BIGGEST_ALIGNMENT_TO_TEST == 0);
template<typename C>
void testVectorAlignment()
@@ -3292,17 +3197,28 @@ void testAssociativeContainerAlignment()
void tst_Collections::alignment()
{
- testVectorAlignment<QVector<Aligned4> >();
- testVectorAlignment<QVector<AlignedBiggest> >();
+ testVectorAlignment<QList<Aligned4> >();
+ testVectorAlignment<QList<AlignedStdMax> >();
+ testVectorAlignment<QList<AlignedBiggest> >();
+
testContiguousCacheAlignment<QContiguousCache<Aligned4> >();
+ testContiguousCacheAlignment<QContiguousCache<AlignedStdMax> >();
testContiguousCacheAlignment<QContiguousCache<AlignedBiggest> >();
+
+ // there's no guarentee that std::map supports over-aligned types
testAssociativeContainerAlignment<QMap<Aligned4, Aligned4> >();
- testAssociativeContainerAlignment<QMap<Aligned4, AlignedBiggest> >();
- testAssociativeContainerAlignment<QMap<AlignedBiggest, Aligned4> >();
- testAssociativeContainerAlignment<QMap<AlignedBiggest, AlignedBiggest> >();
+ testAssociativeContainerAlignment<QMap<Aligned4, AlignedStdMax> >();
+ testAssociativeContainerAlignment<QMap<AlignedStdMax, Aligned4> >();
+ testAssociativeContainerAlignment<QMap<AlignedStdMax, AlignedStdMax> >();
+
testAssociativeContainerAlignment<QHash<Aligned4, Aligned4> >();
+ testAssociativeContainerAlignment<QHash<Aligned4, AlignedStdMax> >();
testAssociativeContainerAlignment<QHash<Aligned4, AlignedBiggest> >();
+ testAssociativeContainerAlignment<QHash<AlignedStdMax, Aligned4> >();
+ testAssociativeContainerAlignment<QHash<AlignedStdMax, AlignedStdMax> >();
+ testAssociativeContainerAlignment<QHash<AlignedStdMax, AlignedBiggest> >();
testAssociativeContainerAlignment<QHash<AlignedBiggest, Aligned4> >();
+ testAssociativeContainerAlignment<QHash<AlignedBiggest, AlignedStdMax> >();
testAssociativeContainerAlignment<QHash<AlignedBiggest, AlignedBiggest> >();
}
@@ -3329,7 +3245,7 @@ template<template<class> class C> void QTBUG13079_collectionInsideCollectionImpl
QCOMPARE(nodeList.first().s, QString::fromLatin1("child"));
nodeList = nodeList.first().children;
- QCOMPARE(nodeList.count(), 0);
+ QCOMPARE(nodeList.size(), 0);
nodeList << QTBUG13079_Node<C>();
}
@@ -3354,12 +3270,12 @@ template<template<class, class> class C> void QTBUG13079_collectionInsideCollect
QCOMPARE(nodeMap[12].s, QString::fromLatin1("child"));
nodeMap = nodeMap[12].children;
- QCOMPARE(nodeMap.count(), 0);
+ QCOMPARE(nodeMap.size(), 0);
nodeMap[42] = QTBUG13079_NodeAssoc<C>();
}
-quint32 qHash(const QTBUG13079_Node<QSet> &)
+size_t qHash(const QTBUG13079_Node<QSet> &)
{
return 0;
}
@@ -3415,14 +3331,13 @@ void tst_Collections::QTBUG13079_collectionInsideCollection()
QTBUG13079_collectionInsideCollectionImpl<QVector>();
QTBUG13079_collectionInsideCollectionImpl<QStack>();
QTBUG13079_collectionInsideCollectionImpl<QList>();
- QTBUG13079_collectionInsideCollectionImpl<QLinkedList>();
QTBUG13079_collectionInsideCollectionImpl<QQueue>();
{
QSet<QTBUG13079_Node<QSet> > nodeSet;
nodeSet << QTBUG13079_Node<QSet>();
nodeSet = nodeSet.begin()->children;
- QCOMPARE(nodeSet.count(), 0);
+ QCOMPARE(nodeSet.size(), 0);
}
QTBUG13079_collectionInsideCollectionAssocImpl<QMap>();
@@ -3444,7 +3359,7 @@ template<class Container> void foreach_test_arrays(const Container &container)
set << val;
i++;
}
- QCOMPARE(set.count(), container.count());
+ QCOMPARE(set.size(), container.size());
//modify the container while iterating.
Container c2 = container;
@@ -3481,9 +3396,9 @@ void tst_Collections::foreach_2()
varl2 << i;
varl3 << i;
}
- QCOMPARE(varl1.count(), intlist.count());
- QCOMPARE(varl2.count(), intlist.count());
- QCOMPARE(varl3.count(), intlist.count());
+ QCOMPARE(varl1.size(), intlist.size());
+ QCOMPARE(varl2.size(), intlist.size());
+ QCOMPARE(varl3.size(), intlist.size());
QVarLengthArray<QString> varl4;
QVarLengthArray<QString, 3> varl5;
@@ -3493,9 +3408,9 @@ void tst_Collections::foreach_2()
varl5 << str;
varl6 << str;
}
- QCOMPARE(varl4.count(), strlist.count());
- QCOMPARE(varl5.count(), strlist.count());
- QCOMPARE(varl6.count(), strlist.count());
+ QCOMPARE(varl4.size(), strlist.size());
+ QCOMPARE(varl5.size(), strlist.size());
+ QCOMPARE(varl6.size(), strlist.size());
}
struct IntOrString
@@ -3516,14 +3431,17 @@ template<class Container> void insert_remove_loop_impl()
t.append(T(IntOrString(1)));
t << (T(IntOrString(2)));
t += (T(IntOrString(3)));
- t.prepend(T(IntOrString(4)));
+ if constexpr (has_prepend_v<Container>)
+ t.prepend(T(IntOrString(4)));
+ else
+ t.insert(t.cbegin(), T(IntOrString(4)));
t.insert(2, 3 , T(IntOrString(5)));
t.insert(4, T(IntOrString(6)));
t.insert(t.begin() + 2, T(IntOrString(7)));
t.insert(t.begin() + 5, 3, T(IntOrString(8)));
int expect1[] = { 4 , 1 , 7, 5 , 5 , 8, 8, 8, 6, 5, 2 , 3 };
- QCOMPARE(size_t(t.count()), sizeof(expect1)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect1)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect1[i])));
}
@@ -3537,8 +3455,8 @@ template<class Container> void insert_remove_loop_impl()
t.remove(7);
t.remove(2, 3);
int expect2[] = { 4 , 1 , 9, 8, 6, 5, 2 , 3 };
- QCOMPARE(size_t(t.count()), sizeof(expect2)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect2)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect2[i])));
}
@@ -3550,16 +3468,16 @@ template<class Container> void insert_remove_loop_impl()
}
int expect3[] = { 1 , 9, 5, 3 };
- QCOMPARE(size_t(t.count()), sizeof(expect3)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect3)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect3[i])));
}
t.erase(t.begin() + 1, t.end() - 1);
int expect4[] = { 1 , 3 };
- QCOMPARE(size_t(t.count()), sizeof(expect4)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect4)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect4[i])));
}
@@ -3576,10 +3494,22 @@ template<class Container> void insert_remove_loop_impl()
int expect5[] = { 1, 1, 2, 3*3, 3, 3*3+1, 10, 11*11, 11, 11*11+1, 12 , 13*13, 13, 13*13+1, 14,
15*15, 15, 15*15+1, 16 , 17*17, 17, 17*17+1 ,18 , 19*19, 19, 19*19+1, 20, 21*21, 21, 21*21+1 };
- QCOMPARE(size_t(t.count()), sizeof(expect5)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect5)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect5[i])));
}
+
+ t.clear();
+ t << T(IntOrString(1)) << T(IntOrString(2)) << T(IntOrString(3)) << T(IntOrString(4));
+ t.insert(2, 4, T(IntOrString(9)));
+ t.insert(2, 4, T(IntOrString(7)));
+
+ int expect6[] = { 1, 2, 7, 7, 7, 7, 9, 9, 9, 9, 3, 4 };
+ QCOMPARE(size_t(t.size()), sizeof(expect6)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
+ QCOMPARE(t[i], T(IntOrString(expect6[i])));
+ }
+
}
@@ -3588,28 +3518,84 @@ using ExtList = QList<T>;
void tst_Collections::insert_remove_loop()
{
- insert_remove_loop_impl<ExtList<int> >();
- insert_remove_loop_impl<ExtList<QString> >();
- insert_remove_loop_impl<QVector<int> >();
- insert_remove_loop_impl<QVector<QString> >();
- insert_remove_loop_impl<QVarLengthArray<int> >();
- insert_remove_loop_impl<QVarLengthArray<QString> >();
- insert_remove_loop_impl<QVarLengthArray<int, 10> >();
- insert_remove_loop_impl<QVarLengthArray<QString, 10> >();
- insert_remove_loop_impl<QVarLengthArray<int, 3> >();
- insert_remove_loop_impl<QVarLengthArray<QString, 3> >();
- insert_remove_loop_impl<QVarLengthArray<int, 15> >();
- insert_remove_loop_impl<QVarLengthArray<QString, 15> >();
-
- insert_remove_loop_impl<ExtList<std::string> >();
- insert_remove_loop_impl<QVector<std::string> >();
- insert_remove_loop_impl<QVarLengthArray<std::string> >();
- insert_remove_loop_impl<QVarLengthArray<std::string, 10> >();
- insert_remove_loop_impl<QVarLengthArray<std::string, 3> >();
- insert_remove_loop_impl<QVarLengthArray<std::string, 15> >();
+ insert_remove_loop_impl<ExtList<int>>();
+ insert_remove_loop_impl<ExtList<QString>>();
+ insert_remove_loop_impl<QList<int>>();
+ insert_remove_loop_impl<QList<QString>>();
+ insert_remove_loop_impl<QVarLengthArray<int>>();
+ insert_remove_loop_impl<QVarLengthArray<QString>>();
+ insert_remove_loop_impl<QVarLengthArray<int, 10>>();
+ insert_remove_loop_impl<QVarLengthArray<QString, 10>>();
+ insert_remove_loop_impl<QVarLengthArray<int, 3>>();
+ insert_remove_loop_impl<QVarLengthArray<QString, 3>>();
+ insert_remove_loop_impl<QVarLengthArray<int, 15>>();
+ insert_remove_loop_impl<QVarLengthArray<QString, 15>>();
+
+ insert_remove_loop_impl<ExtList<std::string>>();
+ insert_remove_loop_impl<QList<std::string>>();
+ insert_remove_loop_impl<QVarLengthArray<std::string>>();
+ insert_remove_loop_impl<QVarLengthArray<std::string, 10>>();
+ insert_remove_loop_impl<QVarLengthArray<std::string, 3>>();
+ insert_remove_loop_impl<QVarLengthArray<std::string, 15>>();
+}
+
+template <template<typename, typename> typename Container>
+void tst_Collections::detachAssociativeContainerImpl()
+{
+ constexpr int RUNS = 50;
+
+ for (int run = 0; run < RUNS; ++run) {
+ Container<int, int> container;
+
+ for (int i = 0; i < 1'000; ++i) {
+ container.insert(i, i);
+ container.insert(i, i); // for multi-keyed containers
+ }
+
+ const auto it = container.constBegin();
+ const auto &key = it.key();
+ const auto &value = it.value();
+ const auto keyCopy = key;
+ const auto valueCopy = value;
+
+ QSemaphore sem1, sem2;
+ auto detachInAnotherThread = [&sem1, &sem2, copy = container]() mutable {
+ sem1.release();
+ sem2.acquire();
+ copy.clear(); // <==
+ };
+
+ QScopedPointer thread(QThread::create(std::move(detachInAnotherThread)));
+ thread->start();
+
+ sem2.release();
+ sem1.acquire();
+
+ // The following call may detach (because the container is
+ // shared), and then use key/value to search+insert.
+ //
+ // This means that key/value, as references, have to be valid
+ // throughout the insertion procedure. Note that they are
+ // references into the container *itself*; and that the
+ // insertion procedure is working on a new (detached) copy of
+ // the container's payload.
+ //
+ // There is now a possible scenario in which the clear() above
+ // finds the copy's refcount at 1, hence not perform a detach,
+ // and destroy its payload. But key/value were references into
+ // *that* payload (it's the payload that `container` itself
+ // used to share). If inside insert() we don't take extra
+ // measures to keep the payload alive, now they're dangling and
+ // the insertion will malfunction.
+
+ container.insert(key, value);
+
+ QVERIFY(container.contains(keyCopy));
+ QCOMPARE(container.value(keyCopy), valueCopy);
+
+ thread->wait();
+ }
}
-
-
QTEST_APPLESS_MAIN(tst_Collections)
#include "tst_collections.moc"
diff --git a/tests/auto/corelib/tools/containerapisymmetry/CMakeLists.txt b/tests/auto/corelib/tools/containerapisymmetry/CMakeLists.txt
new file mode 100644
index 0000000000..0ae1092043
--- /dev/null
+++ b/tests/auto/corelib/tools/containerapisymmetry/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_containerapisymmetry Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_containerapisymmetry LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_containerapisymmetry
+ SOURCES
+ tst_containerapisymmetry.cpp
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro b/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro
deleted file mode 100644
index efdb7fc2df..0000000000
--- a/tests/auto/corelib/tools/containerapisymmetry/containerapisymmetry.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-TARGET = tst_containerapisymmetry
-SOURCES += tst_containerapisymmetry.cpp
-QT = core testlib
-
-DEFINES -= QT_NO_LINKED_LIST
diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
index 0e4517e740..5eb9dbfa36 100644
--- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
+++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp
@@ -1,72 +1,47 @@
-/****************************************************************************
-**
-** 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>
+// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include "qbytearray.h"
-#include "qlinkedlist.h"
+#include "qdebug.h"
+#include "qhash.h"
+#include "qmap.h"
+#include "qset.h"
#include "qlist.h"
#include "qstring.h"
#include "qvarlengtharray.h"
-#include "qvector.h"
-#include "qhash.h"
-#include "qdebug.h"
#include <algorithm>
#include <functional>
-#include <vector> // for reference
+#include <iostream>
#include <list>
#include <set>
+#include <sstream>
#include <map>
-
-// MSVC has these containers from the Standard Library, but it lacks
-// a __has_include mechanism (that we need to use for other stdlibs).
-// For the sake of increasing our test coverage, work around the issue.
-
-#ifdef Q_CC_MSVC
-#define COMPILER_HAS_STDLIB_INCLUDE(x) 1
-#else
-#define COMPILER_HAS_STDLIB_INCLUDE(x) __has_include(x)
-#endif
-
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
#include <forward_list>
-#endif
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
#include <unordered_set>
-#endif
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
#include <unordered_map>
-#endif
+#include <q20vector.h> // For reference
+
+QT_BEGIN_NAMESPACE
+std::ostream &operator<<(std::ostream &os, const QChar &c)
+{
+ Q_ASSERT(c == QLatin1Char{c.toLatin1()});
+ return os << c.toLatin1();
+}
+std::istream &operator>>(std::istream &os, QChar &c)
+{
+ char cL1;
+ os >> cL1;
+ c = QLatin1Char{cL1};
+ return os;
+}
+QT_END_NAMESPACE
struct Movable
{
- explicit Movable(int i = 0) Q_DECL_NOTHROW
+ explicit Movable(int i = 0) noexcept
: i(i)
{
++instanceCount;
@@ -85,14 +60,19 @@ struct Movable
int i;
static int instanceCount;
+
+ friend std::ostream &operator<<(std::ostream &os, const Movable &m)
+ { return os << m.i; }
+ friend std::istream &operator>>(std::istream &os, Movable &m)
+ { return os >> m.i; }
};
int Movable::instanceCount = 0;
-bool operator==(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; }
-bool operator!=(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; }
-bool operator<(Movable lhs, Movable rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; }
+bool operator==(Movable lhs, Movable rhs) noexcept { return lhs.i == rhs.i; }
+bool operator!=(Movable lhs, Movable rhs) noexcept { return lhs.i != rhs.i; }
+bool operator<(Movable lhs, Movable rhs) noexcept { return lhs.i < rhs.i; }
-uint qHash(Movable m, uint seed = 0) Q_DECL_NOTHROW { return qHash(m.i, seed); }
+size_t qHash(Movable m, size_t seed = 0) noexcept { return qHash(m.i, seed); }
QDebug &operator<<(QDebug &d, Movable m)
{
const QDebugStateSaver saver(d);
@@ -100,12 +80,12 @@ QDebug &operator<<(QDebug &d, Movable m)
}
QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
struct Complex
{
- explicit Complex(int i = 0) Q_DECL_NOTHROW
+ explicit Complex(int i = 0) noexcept
: i(i)
{
++instanceCount;
@@ -121,17 +101,24 @@ struct Complex
{
--instanceCount;
}
+ constexpr Complex &operator=(const Complex &o) noexcept
+ { i = o.i; return *this; }
int i;
static int instanceCount;
+
+ friend std::ostream &operator<<(std::ostream &os, const Complex &c)
+ { return os << c.i; }
+ friend std::istream &operator>>(std::istream &os, Complex &c)
+ { return os >> c.i; }
};
int Complex::instanceCount = 0;
-bool operator==(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i == rhs.i; }
-bool operator!=(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i != rhs.i; }
-bool operator<(Complex lhs, Complex rhs) Q_DECL_NOTHROW { return lhs.i < rhs.i; }
+bool operator==(Complex lhs, Complex rhs) noexcept { return lhs.i == rhs.i; }
+bool operator!=(Complex lhs, Complex rhs) noexcept { return lhs.i != rhs.i; }
+bool operator<(Complex lhs, Complex rhs) noexcept { return lhs.i < rhs.i; }
-uint qHash(Complex c, uint seed = 0) Q_DECL_NOTHROW { return qHash(c.i, seed); }
+size_t qHash(Complex c, size_t seed = 0) noexcept { return qHash(c.i, seed); }
QDebug &operator<<(QDebug &d, Complex c)
{
const QDebugStateSaver saver(d);
@@ -141,7 +128,7 @@ QDebug &operator<<(QDebug &d, Complex c)
struct DuplicateStrategyTestType
{
- explicit DuplicateStrategyTestType(int i = 0) Q_DECL_NOTHROW
+ explicit DuplicateStrategyTestType(int i = 0) noexcept
: i(i),
j(++counter)
{
@@ -157,27 +144,27 @@ int DuplicateStrategyTestType::counter = 0;
// only look at the i member, not j. j allows us to identify which instance
// gets inserted in containers that don't allow for duplicates
-bool operator==(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
+bool operator==(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) noexcept
{
return lhs.i == rhs.i;
}
-bool operator!=(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
+bool operator!=(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) noexcept
{
return lhs.i != rhs.i;
}
-bool operator<(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
+bool operator<(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) noexcept
{
return lhs.i < rhs.i;
}
-uint qHash(DuplicateStrategyTestType c, uint seed = 0) Q_DECL_NOTHROW
+size_t qHash(DuplicateStrategyTestType c, size_t seed = 0) noexcept
{
return qHash(c.i, seed);
}
-bool reallyEqual(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) Q_DECL_NOTHROW
+bool reallyEqual(DuplicateStrategyTestType lhs, DuplicateStrategyTestType rhs) noexcept
{
return lhs.i == rhs.i && lhs.j == rhs.j;
}
@@ -193,7 +180,7 @@ namespace std {
template<>
struct hash<Movable>
{
- std::size_t operator()(Movable m) const Q_DECL_NOTHROW
+ std::size_t operator()(Movable m) const noexcept
{
return hash<int>()(m.i);
}
@@ -202,7 +189,7 @@ struct hash<Movable>
template<>
struct hash<Complex>
{
- std::size_t operator()(Complex m) const Q_DECL_NOTHROW
+ std::size_t operator()(Complex m) const noexcept
{
return hash<int>()(m.i);
}
@@ -211,7 +198,7 @@ struct hash<Complex>
template<>
struct hash<DuplicateStrategyTestType>
{
- std::size_t operator()(DuplicateStrategyTestType m) const Q_DECL_NOTHROW
+ std::size_t operator()(DuplicateStrategyTestType m) const noexcept
{
return hash<int>()(m.i);
}
@@ -224,20 +211,7 @@ template<typename T>
class VarLengthArray : public QVarLengthArray<T>
{
public:
-#ifdef Q_COMPILER_INHERITING_CONSTRUCTORS
using QVarLengthArray<T>::QVarLengthArray;
-#else
- template<typename InputIterator>
- VarLengthArray(InputIterator first, InputIterator last)
- : QVarLengthArray<T>(first, last)
- {
- }
-
- VarLengthArray(std::initializer_list<T> args)
- : QVarLengthArray<T>(args)
- {
- }
-#endif
};
class tst_ContainerApiSymmetry : public QObject
@@ -270,19 +244,14 @@ private Q_SLOTS:
void ranged_ctor_std_vector_Complex() { ranged_ctor_non_associative_impl<std::vector<Complex>>(); }
void ranged_ctor_std_vector_duplicates_strategy() { non_associative_container_duplicates_strategy<std::vector>(); }
- void ranged_ctor_QVector_int() { ranged_ctor_non_associative_impl<QVector<int>>(); }
- void ranged_ctor_QVector_char() { ranged_ctor_non_associative_impl<QVector<char>>(); }
- void ranged_ctor_QVector_QChar() { ranged_ctor_non_associative_impl<QVector<QChar>>(); }
- void ranged_ctor_QVector_Movable() { ranged_ctor_non_associative_impl<QVector<Movable>>(); }
- void ranged_ctor_QVector_Complex() { ranged_ctor_non_associative_impl<QVector<Complex>>(); }
- void ranged_ctor_QVector_duplicates_strategy() { non_associative_container_duplicates_strategy<QVector>(); }
-
void ranged_ctor_QVarLengthArray_int() { ranged_ctor_non_associative_impl<QVarLengthArray<int>>(); }
void ranged_ctor_QVarLengthArray_Movable() { ranged_ctor_non_associative_impl<QVarLengthArray<Movable>>(); }
void ranged_ctor_QVarLengthArray_Complex() { ranged_ctor_non_associative_impl<QVarLengthArray<Complex>>(); }
void ranged_ctor_QVarLengthArray_duplicates_strategy() { non_associative_container_duplicates_strategy<VarLengthArray>(); } // note the VarLengthArray passed
void ranged_ctor_QList_int() { ranged_ctor_non_associative_impl<QList<int>>(); }
+ void ranged_ctor_QList_char() { ranged_ctor_non_associative_impl<QList<char>>(); }
+ void ranged_ctor_QList_QChar() { ranged_ctor_non_associative_impl<QList<QChar>>(); }
void ranged_ctor_QList_Movable() { ranged_ctor_non_associative_impl<QList<Movable>>(); }
void ranged_ctor_QList_Complex() { ranged_ctor_non_associative_impl<QList<Complex>>(); }
void ranged_ctor_QList_duplicates_strategy() { non_associative_container_duplicates_strategy<QList>(); }
@@ -292,42 +261,10 @@ private Q_SLOTS:
void ranged_ctor_std_list_Complex() { ranged_ctor_non_associative_impl<std::list<Complex>>(); }
void ranged_ctor_std_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::list>(); }
- void ranged_ctor_std_forward_list_int() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
- ranged_ctor_non_associative_impl<std::forward_list<int>>();
-#else
- QSKIP("<forward_list> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_forward_list_Movable() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
- ranged_ctor_non_associative_impl<std::forward_list<Movable>>();
-#else
- QSKIP("<forward_list> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_forward_list_Complex() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
- ranged_ctor_non_associative_impl<std::forward_list<Complex>>();
-#else
- QSKIP("<forward_list> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_forward_list_duplicates_strategy() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
- non_associative_container_duplicates_strategy<std::forward_list>();
-#else
- QSKIP("<forward_list> is needed for this test");
-#endif
- }
-
- void ranged_ctor_QLinkedList_int() { ranged_ctor_non_associative_impl<QLinkedList<int>>(); }
- void ranged_ctor_QLinkedList_Movable() { ranged_ctor_non_associative_impl<QLinkedList<Movable>>(); }
- void ranged_ctor_QLinkedList_Complex() { ranged_ctor_non_associative_impl<QLinkedList<Complex>>(); }
- void ranged_ctor_QLinkedList_duplicates_strategy() { non_associative_container_duplicates_strategy<QLinkedList>(); }
+ void ranged_ctor_std_forward_list_int() { ranged_ctor_non_associative_impl<std::forward_list<int>>(); }
+ void ranged_ctor_std_forward_list_Movable() {ranged_ctor_non_associative_impl<std::forward_list<Movable>>(); }
+ void ranged_ctor_std_forward_list_Complex() { ranged_ctor_non_associative_impl<std::forward_list<Complex>>(); }
+ void ranged_ctor_std_forward_list_duplicates_strategy() { non_associative_container_duplicates_strategy<std::forward_list>(); }
void ranged_ctor_std_set_int() { ranged_ctor_non_associative_impl<std::set<int>>(); }
void ranged_ctor_std_set_Movable() { ranged_ctor_non_associative_impl<std::set<Movable>>(); }
@@ -339,70 +276,15 @@ private Q_SLOTS:
void ranged_ctor_std_multiset_Complex() { ranged_ctor_non_associative_impl<std::multiset<Complex>>(); }
void ranged_ctor_std_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::multiset>(); }
- void ranged_ctor_std_unordered_set_int() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_set<int>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
+ void ranged_ctor_std_unordered_set_int() { ranged_ctor_non_associative_impl<std::unordered_set<int>>(); }
+ void ranged_ctor_std_unordered_set_Movable() { ranged_ctor_non_associative_impl<std::unordered_set<Movable>>(); }
+ void ranged_ctor_std_unordered_set_Complex() { ranged_ctor_non_associative_impl<std::unordered_set<Complex>>(); }
+ void ranged_ctor_std_unordered_set_duplicates_strategy() { non_associative_container_duplicates_strategy<std::unordered_set>(); }
- void ranged_ctor_std_unordered_set_Movable() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_set<Movable>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_unordered_set_Complex() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_set<Complex>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
- void ranged_ctor_unordered_set_duplicates_strategy() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- non_associative_container_duplicates_strategy<std::unordered_set>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
-
- void ranged_ctor_std_unordered_multiset_int() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_multiset<int>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_unordered_multiset_Movable() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_multiset<Movable>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_unordered_multiset_Complex() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- ranged_ctor_non_associative_impl<std::unordered_multiset<Complex>>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
-
- void ranged_ctor_std_unordered_multiset_duplicates_strategy() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
- non_associative_container_duplicates_strategy<std::unordered_multiset>();
-#else
- QSKIP("<unordered_set> is needed for this test");
-#endif
- }
+ void ranged_ctor_std_unordered_multiset_int() { ranged_ctor_non_associative_impl<std::unordered_multiset<int>>(); }
+ void ranged_ctor_std_unordered_multiset_Movable() { ranged_ctor_non_associative_impl<std::unordered_multiset<Movable>>(); }
+ void ranged_ctor_std_unordered_multiset_Complex() { ranged_ctor_non_associative_impl<std::unordered_multiset<Complex>>(); }
+ void ranged_ctor_std_unordered_multiset_duplicates_strategy() { non_associative_container_duplicates_strategy<std::unordered_multiset>(); }
void ranged_ctor_QSet_int() { ranged_ctor_non_associative_impl<QSet<int>>(); }
void ranged_ctor_QSet_Movable() { ranged_ctor_non_associative_impl<QSet<Movable>>(); }
@@ -418,57 +300,17 @@ private Q_SLOTS:
void ranged_ctor_std_multimap_Movable() { ranged_ctor_associative_impl<std::multimap<Movable, int>>(); }
void ranged_ctor_std_multimap_Complex() { ranged_ctor_associative_impl<std::multimap<Complex, int>>(); }
- void ranged_ctor_unordered_map_int() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_map<int, int>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
-
- void ranged_ctor_unordered_map_Movable() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_map<Movable, Movable>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
-
- void ranged_ctor_unordered_map_Complex() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_map<Complex, Complex>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
+ void ranged_ctor_unordered_map_int() { ranged_ctor_associative_impl<std::unordered_map<int, int>>(); }
+ void ranged_ctor_unordered_map_Movable() { ranged_ctor_associative_impl<std::unordered_map<Movable, Movable>>(); }
+ void ranged_ctor_unordered_map_Complex() { ranged_ctor_associative_impl<std::unordered_map<Complex, Complex>>(); }
void ranged_ctor_QHash_int() { ranged_ctor_associative_impl<QHash<int, int>>(); }
void ranged_ctor_QHash_Movable() { ranged_ctor_associative_impl<QHash<Movable, int>>(); }
void ranged_ctor_QHash_Complex() { ranged_ctor_associative_impl<QHash<Complex, int>>(); }
- void ranged_ctor_unordered_multimap_int() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_multimap<int, int>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
-
- void ranged_ctor_unordered_multimap_Movable() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_multimap<Movable, Movable>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
-
- void ranged_ctor_unordered_multimap_Complex() {
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_map>)
- ranged_ctor_associative_impl<std::unordered_multimap<Complex, Complex>>();
-#else
- QSKIP("<unordered_map> is needed for this test");
-#endif
- }
+ void ranged_ctor_unordered_multimap_int() { ranged_ctor_associative_impl<std::unordered_multimap<int, int>>(); }
+ void ranged_ctor_unordered_multimap_Movable() { ranged_ctor_associative_impl<std::unordered_multimap<Movable, Movable>>(); }
+ void ranged_ctor_unordered_multimap_Complex() { ranged_ctor_associative_impl<std::unordered_multimap<Complex, Complex>>(); }
void ranged_ctor_QMultiHash_int() { ranged_ctor_associative_impl<QMultiHash<int, int>>(); }
void ranged_ctor_QMultiHash_Movable() { ranged_ctor_associative_impl<QMultiHash<Movable, int>>(); }
@@ -476,19 +318,117 @@ private Q_SLOTS:
private:
template <typename Container>
+ void resize_impl() const;
+
+private Q_SLOTS:
+ void resize_std_vector() { resize_impl<std::vector<int>>(); }
+ void resize_QList() { resize_impl<QList<qintptr>>(); }
+ void resize_QVarLengthArray() { resize_impl<QVarLengthArray<int>>(); }
+ void resize_QString() { resize_impl<QString>(); }
+ void resize_QByteArray() { resize_impl<QByteArray>(); }
+
+private:
+ template <typename Container>
+ void copesWithValueTypesWithConstMembers_impl();
+
+ struct ConstMember {
+ #ifndef __cpp_aggregate_paren_init // also check that we can emplace aggregates (C++20 only)
+ explicit ConstMember(int n) : n(n) {}
+ #endif
+ const int n;
+
+ friend bool operator==(const ConstMember &lhs, const ConstMember &rhs) noexcept
+ { return lhs.n == rhs.n; }
+ friend bool operator!=(const ConstMember &lhs, const ConstMember &rhs) noexcept
+ { return !(lhs == rhs); }
+ };
+
+private Q_SLOTS:
+ void copesWithValueTypesWithConstMembers_std_vector() { copesWithValueTypesWithConstMembers_impl<std::vector<ConstMember>>(); }
+ void copesWithValueTypesWithConstMembers_QVarLengthArray() { copesWithValueTypesWithConstMembers_impl<QVarLengthArray<ConstMember, 2>>(); }
+
+private:
+ template <typename Container>
+ void assign_impl() const;
+
+private Q_SLOTS:
+ void assign_std_vector() { assign_impl<std::vector<int>>(); };
+ void assign_std_string() { assign_impl<std::string>(); }
+ void assign_QVarLengthArray() { assign_impl<QVarLengthArray<int, 4>>(); };
+ void assign_QList() { assign_impl<QList<int>>(); }
+ void assign_QByteArray() { assign_impl<QByteArray>(); }
+ void assign_QString() { assign_impl<QString>(); }
+
+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>(); }
+
+private:
+ template <typename Container>
+ void erase_impl() const;
+
+ template <typename Container>
+ void erase_if_impl() const;
+
+ template <typename Container>
+ void erase_if_associative_impl() const;
+
+ template <typename Container>
+ void member_erase_impl() const;
+
+ template <typename Container>
+ void member_erase_associative_impl() const;
+
+ template <typename Container>
+ void member_erase_set_impl() const;
+
+private Q_SLOTS:
+ void erase_QList() { erase_impl<QList<int>>(); }
+ void erase_QVarLengthArray() { erase_impl<QVarLengthArray<int>>(); }
+ void erase_QString() { erase_impl<QString>(); }
+ void erase_QByteArray() { erase_impl<QByteArray>(); }
+ void erase_std_vector() { erase_impl<std::vector<int>>(); }
+
+ void erase_if_QList() { erase_if_impl<QList<int>>(); }
+ void erase_if_QVarLengthArray() { erase_if_impl<QVarLengthArray<int>>(); }
+ void erase_if_QSet() { erase_if_impl<QSet<int>>(); }
+ void erase_if_QString() { erase_if_impl<QString>(); }
+ void erase_if_QByteArray() { erase_if_impl<QByteArray>(); }
+ void erase_if_std_vector() { erase_if_impl<std::vector<int>>(); }
+ void erase_if_QMap() { erase_if_associative_impl<QMap<int, int>>(); }
+ void erase_if_QMultiMap() {erase_if_associative_impl<QMultiMap<int, int>>(); }
+ void erase_if_QHash() { erase_if_associative_impl<QHash<int, int>>(); }
+ void erase_if_QMultiHash() { erase_if_associative_impl<QMultiHash<int, int>>(); }
+
+ void member_erase_QList() { member_erase_impl<QList<int>>(); }
+ void member_erase_QVarLengthArray() { member_erase_impl<QVarLengthArray<int>>(); }
+ void member_erase_QString() { member_erase_impl<QString>(); }
+ void member_erase_QByteArray() { member_erase_impl<QByteArray>(); }
+ void member_erase_QSet() { member_erase_set_impl<QSet<int>>(); }
+
+ void member_erase_QMap() { member_erase_associative_impl<QMap<int, int>>(); }
+ void member_erase_QMultiMap() {member_erase_associative_impl<QMultiMap<int, int>>(); }
+ void member_erase_QHash() { member_erase_associative_impl<QHash<int, int>>(); }
+ void member_erase_QMultiHash() { member_erase_associative_impl<QMultiHash<int, int>>(); }
+
+private:
+ template <typename Container>
+ void keyValueRange_impl() const;
+
+private Q_SLOTS:
+ void keyValueRange_QMap() { keyValueRange_impl<QMap<int, int>>(); }
+ void keyValueRange_QMultiMap() { keyValueRange_impl<QMultiMap<int, int>>(); }
+ void keyValueRange_QHash() { keyValueRange_impl<QHash<int, int>>(); }
+ void keyValueRange_QMultiHash() { keyValueRange_impl<QMultiHash<int, int>>(); }
};
void tst_ContainerApiSymmetry::init()
@@ -547,12 +487,25 @@ void tst_ContainerApiSymmetry::ranged_ctor_non_associative_impl() const
// from itself
const Container c4(reference.begin(), reference.end());
+ // from stringsteam (= pure input_iterator)
+ const Container c5 = [&] {
+ {
+ std::stringstream ss;
+ for (auto &v : values1)
+ ss << v << ' ';
+ ss.seekg(0);
+ return Container(std::istream_iterator<V>{ss},
+ std::istream_iterator<V>{});
+ }
+ }();
+
QCOMPARE(c1, reference);
QCOMPARE(c2a, reference);
QCOMPARE(c2b, reference);
QCOMPARE(c3a, reference);
QCOMPARE(c3b, reference);
QCOMPARE(c4, reference);
+ QCOMPARE(c5, reference);
}
@@ -571,7 +524,7 @@ template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::vector<T...>> : ContainerAcceptsDuplicateValues {};
template<typename ... T>
-struct ContainerDuplicatedValuesStrategy<QVector<T...>> : ContainerAcceptsDuplicateValues {};
+struct ContainerDuplicatedValuesStrategy<QList<T...>> : ContainerAcceptsDuplicateValues {};
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<QVarLengthArray<T...>> : ContainerAcceptsDuplicateValues {};
@@ -582,13 +535,8 @@ struct ContainerDuplicatedValuesStrategy<VarLengthArray<T...>> : ContainerAccept
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::list<T...>> : ContainerAcceptsDuplicateValues {};
-#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::forward_list<T...>> : ContainerAcceptsDuplicateValues {};
-#endif
-
-template<typename ... T>
-struct ContainerDuplicatedValuesStrategy<QLinkedList<T...>> : ContainerAcceptsDuplicateValues {};
// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
template<typename ... T>
@@ -597,14 +545,12 @@ struct ContainerDuplicatedValuesStrategy<std::set<T...>> : ContainerRejectsDupli
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::multiset<T...>> : ContainerAcceptsDuplicateValues {};
-#if COMPILER_HAS_STDLIB_INCLUDE(<unordered_set>)
// assuming https://cplusplus.github.io/LWG/lwg-active.html#2844 resolution
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::unordered_set<T...>> : ContainerRejectsDuplicateValues {};
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<std::unordered_multiset<T...>> : ContainerAcceptsDuplicateValues {};
-#endif
template<typename ... T>
struct ContainerDuplicatedValuesStrategy<QSet<T...>> : ContainerRejectsDuplicateValues {};
@@ -782,36 +728,539 @@ template <typename Container>
Container make(int size)
{
Container c;
- int i = 1;
- while (size--)
- c.push_back(typename Container::value_type(i++));
+ c.reserve(size);
+ using V = typename Container::value_type;
+ int i = 0;
+ std::generate_n(std::inserter(c, c.end()), size, [&i] { return V(++i); });
+ return c;
+}
+
+template <typename Container>
+Container makeAssociative(int size)
+{
+ using K = typename Container::key_type;
+ using V = typename Container::mapped_type;
+ Container c;
+ for (int i = 1; i <= size; ++i)
+ c.insert(K(i), V(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 <> QString make(int size) { return s_string.left(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 <> QByteArray make(int size) { return QByteArray("\1\2\3\4\5\6\7", size); }
template <typename T> T clean(T &&t) { return std::forward<T>(t); }
inline char clean(QLatin1Char ch) { return ch.toLatin1(); }
template <typename Container>
+void tst_ContainerApiSymmetry::resize_impl() const
+{
+ using V = typename Container::value_type;
+ using S = typename Container::size_type;
+ auto c = make<Container>(3);
+ QCOMPARE(c.size(), S(3));
+ c.resize(4, V(5));
+ QCOMPARE(std::size(c), S(4));
+ QCOMPARE(c.back(), V(5));
+
+ // ctor/resize symmetry:
+ {
+ Container c1(S(5), V(4));
+ QCOMPARE(c1.size(), S(5));
+
+ Container c2;
+ c2.resize(S(5), V(4));
+ QCOMPARE(c2.size(), S(5));
+
+ QCOMPARE(c1, c2);
+ }
+}
+
+template <typename T>
+[[maybe_unused]]
+constexpr bool is_vector_v = false;
+template <typename...Args>
+constexpr bool is_vector_v<std::vector<Args...>> = true;
+
+template <typename Container, typename Value>
+void wrap_resize(Container &c, typename Container::size_type n, const Value &v)
+{
+#ifdef __GLIBCXX__ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981
+ if constexpr (is_vector_v<Container>) {
+ while (c.size() < n)
+ c.push_back(v);
+ } else
+#endif
+ {
+ c.resize(n, v);
+ }
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::copesWithValueTypesWithConstMembers_impl()
+{
+ // The problem:
+ //
+ // using V = ConstMember;
+ // V v{42};
+ // assert(v.n == 42); // OK
+ // new (&v) V{24};
+ // assert(v.n == 24); // UB in C++17: v.n could still be 42 (C++17 [basic.life]/8)
+ // // OK in C++20 (C++20 [basic.life]/8)
+ // assert(std::launder(&v)->n == 24); // OK
+ // assert(v.n == 24); // _still_ UB!
+ //
+ // Containers:
+ // - must not expose this problem
+ // - must compile in the first place, even though V
+ // - is not assignable
+ // - is not default-constructible
+
+ using S = typename Container::size_type;
+ using V = typename Container::value_type;
+
+ Container c;
+ // the following are all functions that by rights should not require the type to be
+ // - default-constructible
+ // - assignable
+ // make sure they work
+ c.reserve(S(5));
+ c.shrink_to_fit();
+ wrap_resize(c, 1, V(42));
+ QCOMPARE(c[0], V(42));
+ wrap_resize(c, 2, V(48));
+ QCOMPARE(c[0], V(42));
+ QCOMPARE(c[1], V(48));
+ c.clear();
+ c.emplace_back(24);
+ QCOMPARE(c.front(), V(24));
+ c.push_back(V(41));
+ QCOMPARE(c.back(), V(41));
+ {
+ const auto v142 = V(142);
+ c.push_back(v142);
+ }
+ QCOMPARE(c.size(), S(3));
+ QCOMPARE(c[0], V(24));
+ QCOMPARE(c[1], V(41));
+ QCOMPARE(c[2], V(142));
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::assign_impl() const
+{
+#define CHECK(Arr, ComparisonData, Sz_n, Sz_e) \
+ QCOMPARE(Sz_n, Sz_e); \
+ for (const auto &e : Arr) \
+ QCOMPARE(e, ComparisonData) \
+ /*end*/
+#define RET_CHECK(...) \
+ do { \
+ if constexpr (std::is_void_v<decltype( __VA_ARGS__ )>) { \
+ /* e.g. std::vector */ \
+ __VA_ARGS__ ; \
+ } else { \
+ /* e.g. std::basic_string */ \
+ auto &&r = __VA_ARGS__ ; \
+ QCOMPARE_EQ(&r, &c); \
+ } \
+ } while (false) \
+ /* end */
+ using V = typename Container::value_type;
+ using S = typename Container::size_type;
+ auto tData = V(65);
+ {
+ // fill version
+ auto c = make<Container>(4);
+ const S oldCapacity = c.capacity();
+ RET_CHECK(c.assign(4, tData));
+ CHECK(c, tData, c.size(), S(4));
+ QCOMPARE_EQ(c.capacity(), oldCapacity);
+
+ tData = V(66);
+ c.assign(8, tData); // may reallocate
+ CHECK(c, tData, c.size(), S(8));
+
+ const S grownCapacity = c.capacity();
+ c.assign(0, tData);
+ CHECK(c, tData, c.size(), S(0));
+ QCOMPARE_EQ(c.capacity(), grownCapacity);
+ }
+ {
+ // range version for non input iterator
+ auto c = make<Container>(4);
+ auto iter = make<Container>(1);
+
+ iter.assign(8, tData);
+ RET_CHECK(c.assign(iter.begin(), iter.end())); // may reallocate
+ CHECK(c, tData, c.size(), S(8));
+
+ const S oldCapacity = c.capacity();
+ c.assign(iter.begin(), iter.begin());
+ CHECK(c, tData, c.size(), S(0));
+ QCOMPARE_EQ(c.capacity(), oldCapacity);
+ }
+ {
+ // range version for input iterator
+ auto c = make<Container>(4);
+ const S oldCapacity = c.capacity();
+
+ std::stringstream ss;
+ ss << tData << ' ' << tData << ' ';
+ RET_CHECK(c.assign(std::istream_iterator<V>{ss}, std::istream_iterator<V>{}));
+ CHECK(c, tData, c.size(), S(2));
+ QCOMPARE_EQ(c.capacity(), oldCapacity);
+
+ ss.str("");
+ ss.clear();
+ tData = V(66);
+ ss << tData << ' ' << tData << ' ' << tData << ' ' << tData << ' ';
+ c.assign(std::istream_iterator<V>{ss}, std::istream_iterator<V>{});
+ CHECK(c, tData, c.size(), S(4));
+ QCOMPARE_EQ(c.capacity(), oldCapacity);
+
+ ss.str("");
+ ss.clear();
+ tData = V(67);
+ ss << tData << ' ' << tData << ' ' << tData << ' ' << tData << ' '
+ << tData << ' ' << tData << ' ' << tData << ' ';
+ c.assign(std::istream_iterator<V>{ss}, std::istream_iterator<V>{}); // may reallocate
+ CHECK(c, tData, c.size(), S(7));
+ }
+ {
+ // initializer-list version
+ auto c = make<Container>(4);
+ const S oldCapacity = c.capacity();
+ std::initializer_list<V> list = {tData, tData, tData};
+ RET_CHECK(c.assign(list));
+ CHECK(c, tData, c.size(), S(3));
+ QCOMPARE_EQ(c.capacity(), oldCapacity);
+ }
+
+#undef RET_CHECK
+#undef CHECK
+}
+
+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));
+ QCOMPARE(clean(std::as_const(c1).front()), V(1));
+ QCOMPARE(clean(std::as_const(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));
+ QCOMPARE(clean(std::as_const(c2).front()), V(1));
+ QCOMPARE(clean(std::as_const(c2).back()), V(2));
+}
+
+namespace {
+struct Conv {
+ template <typename T>
+ static int toInt(T i) { return i; }
+ static int toInt(QChar ch) { return ch.unicode(); }
+};
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::erase_impl() const
+{
+ using S = typename Container::size_type;
+ using V = typename Container::value_type;
+ auto c = make<Container>(7); // {1, 2, 3, 4, 5, 6, 7}
+ QCOMPARE(c.size(), S(7));
+
+ using q20::erase; // For std::vector
+ auto result = erase(c, V(1));
+ QCOMPARE(result, S(1));
+ QCOMPARE(c.size(), S(6));
+
+ result = erase(c, V(5));
+ QCOMPARE(result, S(1));
+ QCOMPARE(c.size(), S(5));
+
+ result = erase(c, V(123));
+ QCOMPARE(result, S(0));
+ QCOMPARE(c.size(), S(5));
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::erase_if_impl() const
+{
+ using S = typename Container::size_type;
+ using V = typename Container::value_type;
+ auto c = make<Container>(7); // {1, 2, 3, 4, 5, 6, 7}
+ QCOMPARE(c.size(), S(7));
+
+ decltype(c.size()) oldSize, count;
+
+ oldSize = c.size();
+ count = 0;
+
+ using q20::erase_if; // For std::vector
+
+ S result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 2 == 0; });
+ QCOMPARE(result, S(3));
+ QCOMPARE(c.size(), S(4));
+ QCOMPARE(count, oldSize);
+
+ oldSize = c.size();
+ count = 0;
+ result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 123 == 0; });
+ QCOMPARE(result, S(0));
+ QCOMPARE(c.size(), S(4));
+ QCOMPARE(count, oldSize);
+
+ oldSize = c.size();
+ count = 0;
+ result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 3 == 0; });
+ QCOMPARE(result, S(1));
+ QCOMPARE(c.size(), S(3));
+ QCOMPARE(count, oldSize);
+
+ oldSize = c.size();
+ count = 0;
+ result = erase_if(c, [&](V i) { ++count; return Conv::toInt(i) % 2 == 1; });
+ QCOMPARE(result, S(3));
+ QCOMPARE(c.size(), S(0));
+ QCOMPARE(count, oldSize);
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::erase_if_associative_impl() const
+{
+ using S = typename Container::size_type;
+ using K = typename Container::key_type;
+ using V = typename Container::mapped_type;
+ using I = typename Container::iterator;
+ using P = std::pair<const K &, V &>;
+
+ auto c = makeAssociative<Container>(20);
+ QCOMPARE(c.size(), S(20));
+
+ auto result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 2 == 0; });
+ QCOMPARE(result, S(10));
+ QCOMPARE(c.size(), S(10));
+
+ result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 3 == 0; });
+ QCOMPARE(result, S(3));
+ QCOMPARE(c.size(), S(7));
+
+ result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 42 == 0; });
+ QCOMPARE(result, S(0));
+ QCOMPARE(c.size(), S(7));
+
+ result = erase_if(c, [](const P &p) { return Conv::toInt(p.first) % 2 == 1; });
+ QCOMPARE(result, S(7));
+ QCOMPARE(c.size(), S(0));
+
+ // same, but with a predicate taking a Qt iterator
+ c = makeAssociative<Container>(20);
+ QCOMPARE(c.size(), S(20));
+
+ result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 2 == 0; });
+ QCOMPARE(result, S(10));
+ QCOMPARE(c.size(), S(10));
+
+ result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 3 == 0; });
+ QCOMPARE(result, S(3));
+ QCOMPARE(c.size(), S(7));
+
+ result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 42 == 0; });
+ QCOMPARE(result, S(0));
+ QCOMPARE(c.size(), S(7));
+
+ result = erase_if(c, [](const I &it) { return Conv::toInt(it.key()) % 2 == 1; });
+ QCOMPARE(result, S(7));
+ QCOMPARE(c.size(), S(0));
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::member_erase_impl() const
+{
+ using S = typename Container::size_type;
+ using V = typename Container::value_type;
+ const S size = 7;
+ auto c = make<Container>(size); // {1, 2, 3, 4, 5, 6, 7}
+ QCOMPARE(c.size(), size);
+
+ auto copy = c;
+ // Container::erase() returns an iterator, not const_iterator
+ auto it = c.erase(c.cbegin(), c.cbegin());
+ static_assert(std::is_same_v<decltype(it), typename Container::iterator>);
+ QCOMPARE(c.size(), size);
+ const V newVal{100};
+ QCOMPARE_NE(*it, newVal);
+ *it = newVal;
+ QCOMPARE(it, c.cbegin());
+ QCOMPARE(*c.cbegin(), newVal);
+
+ QCOMPARE(std::find(copy.cbegin(), copy.cend(), newVal), copy.cend());
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::member_erase_associative_impl() const
+{
+ using S = typename Container::size_type;
+ using V = typename Container::mapped_type;
+
+ const S size = 20;
+ auto c = makeAssociative<Container>(size);
+ QCOMPARE(c.size(), size);
+
+ // Verify Container::erase() returns iterator, not const_iterator
+ auto it = c.erase(c.cbegin());
+ static_assert(std::is_same_v<decltype(it), typename Container::iterator>);
+ QCOMPARE(c.size(), size - 1);
+ QCOMPARE(it, c.cbegin());
+ const auto current = it.value();
+ it.value() = current + V(5);
+ QCOMPARE(c.cbegin().value(),current + V(5));
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::member_erase_set_impl() const
+{
+ using S = typename Container::size_type;
+
+ const S size = 20;
+ auto c = make<Container>(size);
+ QCOMPARE(c.size(), size);
+
+ // Verify Container::erase() returns iterator, not const_iterator
+ auto it = c.erase(c.cbegin());
+ static_assert(std::is_same_v<decltype(it), typename Container::iterator>);
+ QCOMPARE(c.size(), size - 1);
+ QCOMPARE(it, c.cbegin());
+}
+
+template <typename Container>
+void tst_ContainerApiSymmetry::keyValueRange_impl() const
+{
+ constexpr int COUNT = 20;
+
+ using K = typename Container::key_type;
+ using V = typename Container::mapped_type;
+ QVector<K> keys;
+ keys.reserve(COUNT);
+ QVector<V> values;
+ values.reserve(COUNT);
+
+ auto c = makeAssociative<Container>(COUNT);
+ auto returnC = [&](){ return c; };
+
+ const auto verify = [](QVector<K> v, int count, int offset = 0) -> bool {
+ if (v.size() != count)
+ return false;
+ std::sort(v.begin(), v.end());
+ for (int i = 0; i < count; ++i) {
+ // vector is indexed from 0, but makeAssociative starts from 1
+ if (v[i] != i + 1 + offset)
+ return false;
+ }
+ return true;
+ };
+
+ // Check that the range has the right size
+ auto range = c.asKeyValueRange();
+ QCOMPARE(std::distance(range.begin(), range.end()), COUNT);
+
+ auto constRange = std::as_const(c).asKeyValueRange();
+ QCOMPARE(std::distance(constRange.begin(), constRange.end()), COUNT);
+
+ auto rvalueRange = returnC().asKeyValueRange();
+ QCOMPARE(std::distance(rvalueRange.begin(), rvalueRange.end()), COUNT);
+
+ // auto, mutating
+ keys.clear(); values.clear();
+ for (auto [key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value);
+ QCOMPARE(c.value(key), value);
+ ++value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT));
+
+ // auto, non-mutating
+ keys.clear(); values.clear();
+ for (auto [key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 1));
+
+ // auto &&, mutating
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : c.asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 1);
+ QCOMPARE(c.value(key), value);
+ ++value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 1));
+
+ // auto, non-mutating (const map)
+ keys.clear(); values.clear();
+ for (auto [key, value] : std::as_const(c).asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto &&, non-mutating (const map)
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : std::as_const(c).asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto, non-mutating (rvalue map)
+ keys.clear(); values.clear();
+ for (auto [key, value] : returnC().asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
+
+ // auto &&, non-mutating (rvalue map)
+ keys.clear(); values.clear();
+ for (auto &&[key, value] : returnC().asKeyValueRange()) {
+ keys << key;
+ values << value;
+ QCOMPARE(key, value - 2);
+ QCOMPARE(c.value(key), value);
+ }
+ QVERIFY(verify(keys, COUNT));
+ QVERIFY(verify(values, COUNT, 2));
}
QTEST_APPLESS_MAIN(tst_ContainerApiSymmetry)
diff --git a/tests/auto/corelib/tools/qalgorithms/CMakeLists.txt b/tests/auto/corelib/tools/qalgorithms/CMakeLists.txt
new file mode 100644
index 0000000000..9e87144a4c
--- /dev/null
+++ b/tests/auto/corelib/tools/qalgorithms/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qalgorithms Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qalgorithms LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qalgorithms
+ SOURCES
+ tst_qalgorithms.cpp
+)
diff --git a/tests/auto/corelib/tools/qalgorithms/qalgorithms.pro b/tests/auto/corelib/tools/qalgorithms/qalgorithms.pro
deleted file mode 100644
index 0e6e830185..0000000000
--- a/tests/auto/corelib/tools/qalgorithms/qalgorithms.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qalgorithms
-QT = core testlib
-SOURCES = tst_qalgorithms.cpp
diff --git a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
index 18432e51a6..8d68a7a270 100644
--- a/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
+++ b/tests/auto/corelib/tools/qalgorithms/tst_qalgorithms.cpp
@@ -1,33 +1,10 @@
-/****************************************************************************
-**
-** 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "../../../../../src/corelib/tools/qalgorithms.h"
-#include <QtTest/QtTest>
+#include <QTest>
+
+QT_WARNING_DISABLE_DEPRECATED
#include <iostream>
#include <iomanip>
@@ -35,10 +12,10 @@
#include <iterator>
#include <algorithm>
#include <qalgorithms.h>
-#include <QStringList>
-#include <QString>
+#include <QList>
#include <QRandomGenerator>
-#include <QVector>
+#include <QString>
+#include <QStringList>
#define Q_TEST_PERFORMANCE 0
@@ -52,31 +29,6 @@ private slots:
void swap2();
void convenienceAPI();
-#if QT_DEPRECATED_SINCE(5, 2)
- void test_qLowerBound_data();
- void test_qLowerBound();
- void test_qUpperBound_data();
- void test_qUpperBound();
- void test_qBinaryFind_data();
- void test_qBinaryFind();
- void qBinaryFindOneEntry();
- void sortEmptyList();
- void sortedList();
- void sortAPItest();
- void stableSortTest();
- void stableSortCorrectnessTest_data();
- void stableSortCorrectnessTest();
- void convenienceAPI_deprecated();
- void qCountIterators() const;
- void qCountContainer() const;
- void binaryFindOnLargeContainer() const;
-
-#if Q_TEST_PERFORMANCE
- void performance();
-#endif
-
-#endif // QT_DEPRECATED_SINCE(5, 2)
-
void popCount08_data() { popCount_data_impl(sizeof(quint8 )); }
void popCount16_data() { popCount_data_impl(sizeof(quint16)); }
void popCount32_data() { popCount_data_impl(sizeof(quint32)); }
@@ -118,155 +70,18 @@ private:
void countLeading_impl();
};
-#if QT_DEPRECATED_SINCE(5, 2)
-
-class TestInt
+template <typename T> struct PrintIfFailed
{
-public:
- TestInt(int number) :m_number(number) {} ;
- TestInt() : m_number(0) {};
- bool operator<(const TestInt &other) const { ++TestInt::lessThanRefCount; return (m_number < other.m_number); }
- int m_number;
-static long int lessThanRefCount;
-};
-
-long int TestInt::lessThanRefCount;
-
-
-QStringList dataSetTypes = QStringList() << "Random" << "Ascending"
- << "Descending" << "Equal" << "Duplicates" << "Almost Sorted" ;
-
-template <typename DataType>
-QVector<DataType> generateData(QString dataSetType, const int length)
-{
- QVector<DataType> container;
- if (dataSetType == "Random") {
- for (int i = 0; i < length; ++i)
- container.append(QRandomGenerator::global()->generate());
- } else if (dataSetType == "Ascending") {
- for (int i = 0; i < length; ++i)
- container.append(i);
- } else if (dataSetType == "Descending") {
- for (int i = 0; i < length; ++i)
- container.append(length - i);
- } else if (dataSetType == "Equal") {
- for (int i = 0; i < length; ++i)
- container.append(43);
- } else if (dataSetType == "Duplicates") {
- for (int i = 0; i < length; ++i)
- container.append(i % 10);
- } else if (dataSetType == "Almost Sorted") {
- for (int i = 0; i < length; ++i)
- container.append(i);
- for (int i = 0; i <= length / 10; ++i) {
- const int iswap = i * 9;
- DataType tmp = container.at(iswap);
- container[iswap] = container.at(iswap + 1);
- container[iswap + 1] = tmp;
- }
+ T value;
+ PrintIfFailed(T v) : value(v) {}
+ ~PrintIfFailed()
+ {
+ if (!QTest::currentTestFailed())
+ return;
+ qWarning() << "Original value was" << Qt::hex << Qt::showbase << T(value);
}
- return container;
-}
-
-struct ResultSet
-{
- int numSorts;
- long int lessThanRefCount;
};
-
-template <typename ContainerType, typename Algorithm>
-ResultSet testRun(ContainerType &container, Algorithm &algorithm, int millisecs)
-{
- TestInt::lessThanRefCount = 0;
- int count = 0;
- QElapsedTimer t;
- t.start();
- while(t.elapsed() < millisecs) {
- ++count;
- algorithm(container);
- }
- ResultSet result;
- result.numSorts = count;
- result.lessThanRefCount = TestInt::lessThanRefCount;
- return result;
-}
-
-template <typename ContainerType, typename LessThan>
-bool isSorted(ContainerType &container, LessThan lessThan)
-{
- for (int i=0; i < container.count() - 1; ++i)
- if (lessThan(container.at(i+1), container.at(i))) {
- return false;
- }
- return true;
-}
-
-template <typename ContainerType>
-bool isSorted(ContainerType &container)
-{
- return isSorted(container, qLess<typename ContainerType::value_type>());
-}
-
-
-#if Q_TEST_PERFORMANCE
-void printHeader(QStringList &headers)
-{
- cout << setw(10) << setiosflags(ios_base::left) << " ";
- for (int h = 0; h < headers.count(); ++h) {
- cout << setw(20) << setiosflags(ios_base::left) << headers.at(h).toLatin1().constData();
- }
- cout << Qt::endl;
-}
-
-template <typename ContainerType>
-void print(ContainerType testContainer)
-{
- typedef typename ContainerType::value_type T;
-
- foreach(T value, testContainer) {
- cout << value << " ";
- }
-
- cout << Qt::endl;
-}
-
-template <typename Algorithm, typename DataType>
-QList<ResultSet> testAlgorithm(Algorithm &algorithm, QStringList dataSetTypes, int size, int time)
-{
- QList<ResultSet> results;
- foreach(QString dataSetType, dataSetTypes) {
- QVector<DataType> container = generateData<DataType>(dataSetType, size);
- results.append(testRun(container, algorithm, time));
- if (!isSorted(container))
- qWarning("%s: container is not sorted after test", Q_FUNC_INFO);
- }
- return results;
-}
-
-template <typename Algorithm, typename DataType>
-void testAlgorithm(Algorithm algorithm, QStringList &dataSetTypes)
-{
- QList<int> sizes = QList<int>() << 5 << 15 << 35 << 70 << 200 << 1000 << 10000;
- printHeader(dataSetTypes);
- for (int s = 0; s < sizes.count(); ++s){
- cout << setw(10) << setiosflags(ios_base::left)<< sizes.at(s);
- QList<ResultSet> results =
- testAlgorithm<Algorithm, DataType>(algorithm, dataSetTypes, sizes.at(s), 100);
- foreach(ResultSet result, results) {
- stringstream numSorts;
- numSorts << setiosflags(ios_base::left) << setw(10) << result.numSorts;
- stringstream lessThan;
- lessThan << setiosflags(ios_base::left) << setw(10) << result.lessThanRefCount / result.numSorts;
- cout << numSorts.str() << lessThan.str();
- }
- cout << Qt::endl;
- }
-}
-#endif
-
-#endif // QT_DEPRECATED_SINCE(5, 2)
-
void tst_QAlgorithms::swap()
{
{
@@ -339,42 +154,42 @@ void tst_QAlgorithms::swap()
}
{
- void *a = 0, *b = 0;
+ void *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
- const void *a = 0, *b = 0;
+ const void *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
- QString *a = 0, *b = 0;
+ QString *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
- const QString *a = 0, *b = 0;
+ const QString *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
- QString **a = 0, **b = 0;
+ QString **a = nullptr, **b = nullptr;
qSwap(a, b);
}
{
- const QString **a = 0, **b = 0;
+ const QString **a = nullptr, **b = nullptr;
qSwap(a, b);
}
{
- QString * const *a = 0, * const *b = 0;
+ QString * const *a = nullptr, * const *b = nullptr;
qSwap(a, b);
}
{
- const QString * const *a = 0, * const *b = 0;
+ const QString * const *a = nullptr, * const *b = nullptr;
qSwap(a, b);
}
}
@@ -410,676 +225,26 @@ void tst_QAlgorithms::convenienceAPI()
qDeleteAll(pointerList.begin(), pointerList.end());
}
-#if QT_DEPRECATED_SINCE(5, 2)
-
-void tst_QAlgorithms::sortEmptyList()
-{
- // Only test if it crashes
- QStringList stringList;
- stringList.sort();
- QVERIFY(true);
-}
-
-void tst_QAlgorithms::sortedList()
-{
- QList<int> list;
- list << 4 << 3 << 6;
-
- ::qSort(list.begin(), list.end());
-
- QCOMPARE(list.count(), 3);
- QCOMPARE(list.at(0), 3);
- QCOMPARE(list.at(1), 4);
- QCOMPARE(list.at(2), 6);
-
- list.insert(qUpperBound(list.begin(), list.end(), 5), 5);
- list.insert(qUpperBound(list.begin(), list.end(), 1), 1);
- list.insert(qUpperBound(list.begin(), list.end(), 8), 8);
-
- QCOMPARE(list.count(), 6);
- QCOMPARE(list.at(0), 1);
- QCOMPARE(list.at(1), 3);
- QCOMPARE(list.at(2), 4);
- QCOMPARE(list.at(3), 5);
- QCOMPARE(list.at(4), 6);
- QCOMPARE(list.at(5), 8);
-}
-
-
-void tst_QAlgorithms::test_qLowerBound_data()
-{
- QTest::addColumn<QList<int> >("data");
- QTest::addColumn<int>("resultValue");
- QTest::addColumn<int>("resultIndex");
-
- QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2 << 1;
-}
-
-void tst_QAlgorithms::test_qLowerBound()
-{
- QFETCH(QList<int>, data);
- QFETCH(int, resultValue);
- QFETCH(int, resultIndex);
-
-
- QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex);
- QCOMPARE(qLowerBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex);
- QCOMPARE(qLowerBound(data, resultValue), data.constBegin() + resultIndex);
- QCOMPARE(qLowerBound(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), data.constBegin() + resultIndex);
-}
-
-void tst_QAlgorithms::test_qUpperBound_data()
-{
- QTest::addColumn<QList<int> >("data");
- QTest::addColumn<int>("resultValue");
- QTest::addColumn<int>("resultIndex");
-
- QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2 << 3;
-}
-
-void tst_QAlgorithms::test_qUpperBound()
-{
- QFETCH(QList<int>, data);
- QFETCH(int, resultValue);
- QFETCH(int, resultIndex);
-
- QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue), data.constBegin() + resultIndex);
- QCOMPARE(qUpperBound(data.begin(), data.end(), resultValue), data.begin() + resultIndex);
- QCOMPARE(qUpperBound(data, resultValue), data.constBegin() + resultIndex);
- QCOMPARE(qUpperBound(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), data.constBegin() + resultIndex);
-}
-
-void tst_QAlgorithms::test_qBinaryFind_data()
-{
- QTest::addColumn<QList<int> >("data");
- QTest::addColumn<int>("resultValue"); // -42 means not found
-
- QTest::newRow("sorted-duplicate") << (QList<int>() << 1 << 2 << 2 << 3) << 2;
- QTest::newRow("sorted-end") << (QList<int>() << -5 << -2 << 0 << 8) << 8;
- QTest::newRow("sorted-beginning") << (QList<int>() << -5 << -2 << 0 << 8) << -5;
- QTest::newRow("sorted-duplicate-beginning") << (QList<int>() << -5 << -5 << -2 << 0 << 8) << -5;
- QTest::newRow("empty") << (QList<int>()) << -42;
- QTest::newRow("not found 1 ") << (QList<int>() << 1 << 5 << 8 << 65) << -42;
- QTest::newRow("not found 2 ") << (QList<int>() << -456 << -5 << 8 << 65) << -42;
-}
-
-void tst_QAlgorithms::test_qBinaryFind()
-{
- QFETCH(QList<int>, data);
- QFETCH(int, resultValue);
-
- //-42 means not found
- if (resultValue == -42) {
- QVERIFY(qBinaryFind(data.constBegin(), data.constEnd(), resultValue) == data.constEnd());
- QVERIFY(qBinaryFind(data, resultValue) == data.constEnd());
- QVERIFY(qBinaryFind(data.begin(), data.end(), resultValue) == data.end());
- QVERIFY(qBinaryFind(data.begin(), data.end(), resultValue, qLess<int>()) == data.end());
- return;
- }
-
- QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue), resultValue);
- QCOMPARE(*qBinaryFind(data.begin(), data.end(), resultValue), resultValue);
- QCOMPARE(*qBinaryFind(data, resultValue), resultValue);
- QCOMPARE(*qBinaryFind(data.constBegin(), data.constEnd(), resultValue, qLess<int>()), resultValue);
-}
-
-void tst_QAlgorithms::qBinaryFindOneEntry()
-{
- QList<int> list;
- list << 2;
-
- QVERIFY(::qBinaryFind(list.constBegin(), list.constEnd(), 2) != list.constEnd());
-}
-
-
-void tst_QAlgorithms::sortAPItest()
-{
- QVector<int> testVector = generateData<int>("Random", 101);
- qSort(testVector);
- QVERIFY(isSorted(testVector));
- qSort(testVector.begin(), testVector.end());
- QVERIFY(isSorted(testVector));
- qSort(testVector.begin(), testVector.end(), qLess<int>());
- QVERIFY(isSorted(testVector));
-
- testVector = generateData<int>("Random", 71);
- qStableSort(testVector);
- QVERIFY(isSorted(testVector));
- qStableSort(testVector.begin(), testVector.end());
- QVERIFY(isSorted(testVector));
- qStableSort(testVector.begin(), testVector.end(), qLess<int>());
- QVERIFY(isSorted(testVector));
-
- QList<int> testList = generateData<int>("Random", 101).toList();
- qSort(testList);
- QVERIFY(isSorted(testList));
- qSort(testList.begin(), testList.end());
- QVERIFY(isSorted(testList));
- qSort(testList.begin(), testList.end(), qLess<int>());
- QVERIFY(isSorted(testList));
-
- testList = generateData<int>("Random", 71).toList();
- qStableSort(testList);
- QVERIFY(isSorted(testList));
- qStableSort(testList.begin(), testList.end());
- QVERIFY(isSorted(testList));
- qStableSort(testList.begin(), testList.end(), qLess<int>());
- QVERIFY(isSorted(testList));
-}
-
-
-class StableSortTest
-{
-public:
- StableSortTest(){};
- StableSortTest(int Major, int Minor) : Major(Major), Minor(Minor) {}
- bool operator<(const StableSortTest &other) const {return (Major < other.Major); }
- bool testMinor(const StableSortTest &other) const {return Minor < other.Minor; }
-
-int Major;
-int Minor;
-};
-
-ostream &operator<<(ostream &out, const StableSortTest& obj) { out << obj.Major << "-" << obj.Minor; return out; }
-
-QVector<StableSortTest> createStableTestVector()
-{
- QVector<StableSortTest> stableTestVector;
- for (int i=500; i>=0; --i) {
- for (int j=0; j<10; ++j) {
- stableTestVector.append(StableSortTest(i, j));
- }
- }
- return stableTestVector;
-}
-
-template <typename ContainerType, typename LessThan>
-bool isStableSorted(ContainerType &container, LessThan lessThan)
-{
- for (int i=0; i < container.count() - 1; ++i) {
- //not sorted?
- if (lessThan(container.at(i + 1), container.at(i)))
- return false;
- // equal?
- if (lessThan(container.at(i), container.at(i + 1)))
- continue;
- // minor version?
- if(container.at(i + 1).testMinor(container.at(i)))
- return false;
- }
- return true;
-}
-
-void tst_QAlgorithms::stableSortTest()
-{
- // Selftests:
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- qSort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>()));
- QVERIFY(!isStableSorted(stableTestVector, qLess<StableSortTest>()));
- }
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- qSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>()));
- QVERIFY(!isStableSorted(stableTestVector, qGreater<StableSortTest>()));
- }
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- qSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>());
- QVERIFY(!isSorted(stableTestVector, qLess<StableSortTest>()));
- QVERIFY(!isStableSorted(stableTestVector, qGreater<StableSortTest>()));
- }
-
-
- // Stable sort with qLess
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- std::stable_sort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>()));
- QVERIFY(isStableSorted(stableTestVector, qLess<StableSortTest>()));
- }
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- qStableSort(stableTestVector.begin(), stableTestVector.end(), qLess<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qLess<StableSortTest>()));
- QVERIFY(isStableSorted(stableTestVector, qLess<StableSortTest>()));
- }
-
- // Stable sort with qGreater
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- std::stable_sort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>()));
- QVERIFY(isStableSorted(stableTestVector, qGreater<StableSortTest>()));
- }
-
- {
- QVector<StableSortTest> stableTestVector = createStableTestVector();
- qStableSort(stableTestVector.begin(), stableTestVector.end(), qGreater<StableSortTest>());
- QVERIFY(isSorted(stableTestVector, qGreater<StableSortTest>()));
- QVERIFY(isStableSorted(stableTestVector, qGreater<StableSortTest>()));
- }
-}
-
-
-void tst_QAlgorithms::stableSortCorrectnessTest_data()
-{
- const int dataSize = 1000;
- QTest::addColumn<QVector<int> >("unsorted");
- QTest::newRow("From documentation") << (QVector<int>() << 33 << 12 << 68 << 6 << 12);
- QTest::newRow("Equal") << (generateData<int>("Equal", dataSize));
- QTest::newRow("Ascending") << (generateData<int>("Ascending", dataSize));
- QTest::newRow("Descending") << (generateData<int>("Descending", dataSize));
- QTest::newRow("Duplicates") << (generateData<int>("Duplicates", dataSize));
- QTest::newRow("Almost Sorted") << (generateData<int>("Almost Sorted", dataSize));
- QTest::newRow("Random") << (generateData<int>("Random", dataSize));
-}
-
-void tst_QAlgorithms::stableSortCorrectnessTest()
-{
- QFETCH(QVector<int>, unsorted);
-
- QVector<int> sorted = unsorted;
- qStableSort(sorted.begin(), sorted.end());
-
- // Verify that sorted contains the same numbers as unsorted.
- foreach(int value, unsorted) {
- QVERIFY(sorted.contains(value));
- int unsortedCount = 0;
- qCount(unsorted.begin(), unsorted.end(), value, unsortedCount);
- int sortedCount = 0;
- qCount(sorted.begin(), sorted.end(), value, sortedCount);
- QCOMPARE(sortedCount, unsortedCount);
- }
-
- QVERIFY(isSorted(sorted));
-}
-
-void tst_QAlgorithms::convenienceAPI_deprecated()
-{
- // Compile-test for QAlgorithm convenience functions.
- QList<int> list, list2;
-
- qCopy(list.begin(), list.end(), list2.begin());
- qCopyBackward(list.begin(), list.end(), list2.begin());
- qEqual(list.begin(), list.end(), list2.begin());
-
- qFill(list, 1);
- qFill(list.begin(), list.end(), 1);
-
- qFind(list, 1);
- qFind(list.begin(), list.end(), 1);
-
- int count1 = 0 , count2 = 0, count3 = 0;
- qCount(list, 1, count1);
- qCount(list.begin(), list.end(), 1, count2);
- QCOMPARE(count1, count2);
- QCOMPARE(count2, count3);
-
- qSort(list);
- qSort(list.begin(), list.end());
- qSort(list.begin(), list.end(), qLess<int>());
-
- qStableSort(list);
- qStableSort(list.begin(), list.end());
- qStableSort(list.begin(), list.end(), qLess<int>());
-
- qLowerBound(list, 1);;
- qLowerBound(list.begin(), list.end(), 1);
- qLowerBound(list.begin(), list.end(), 1, qLess<int>());
-
- qUpperBound(list, 1);
- qUpperBound(list.begin(), list.end(), 1);
- qUpperBound(list.begin(), list.end(), 1, qLess<int>());
-
- qBinaryFind(list, 1);
- qBinaryFind(list.begin(), list.end(), 1);
- qBinaryFind(list.begin(), list.end(), 1, qLess<int>());
-}
-
-template <typename DataType>
-class QuickSortHelper
-{
-public:
- void operator()(QVector<DataType> list)
- {
- ::qSort(list);
- }
-};
-
-template <typename DataType>
-class StableSortHelper
-{
-public:
- void operator()(QVector<DataType> list)
- {
- ::qStableSort(list);
- }
-};
-
-template <typename DataType>
-class StlSortHelper
-{
-public:
- void operator()(QVector<DataType> list)
- {
- std::sort(list.begin(), list.end());
- }
-};
-
-template <typename DataType>
-class StlStableSortHelper
-{
-public:
- void operator()(QVector<DataType> list)
- {
- std::stable_sort(list.begin(), list.end());
- }
-};
-
-#if Q_TEST_PERFORMANCE
-void tst_QAlgorithms::performance()
-{
- cout << Qt::endl << "Quick sort" << Qt::endl;
- testAlgorithm<QuickSortHelper<TestInt>, TestInt>(QuickSortHelper<TestInt>(), dataSetTypes);
- cout << Qt::endl << "stable sort" << Qt::endl;
- testAlgorithm<StableSortHelper<TestInt>, TestInt>(StableSortHelper<TestInt>(), dataSetTypes);
- cout << Qt::endl << "std::sort" << Qt::endl;
- testAlgorithm<StlSortHelper<TestInt>, TestInt>(StlSortHelper<TestInt>(), dataSetTypes);
- cout << Qt::endl << "std::stable_sort" << Qt::endl;
- testAlgorithm<StlStableSortHelper<TestInt>, TestInt>(StlStableSortHelper<TestInt>(), dataSetTypes);
-/*
- cout << Qt::endl << "Sorting lists of ints" << Qt::endl;
- cout << Qt::endl << "Quick sort" << Qt::endl;
- testAlgorithm<QuickSortHelper<int>, int>(QuickSortHelper<int>(), dataSetTypes);
- cout << Qt::endl << "std::sort" << Qt::endl;
- testAlgorithm<StlSortHelper<int>, int>(StlSortHelper<int>(), dataSetTypes);
- cout << Qt::endl << "std::stable_sort" << Qt::endl;
- testAlgorithm<StlStableSortHelper<int>, int>(StlStableSortHelper<int>(), dataSetTypes);
-*/
-}
-#endif
-
-void tst_QAlgorithms::qCountIterators() const
-{
- QList<int> list;
- list << 3 << 3 << 6 << 6 << 6 << 8;
-
- {
- int countOf7 = 0;
- ::qCount(list.begin(), list.end(), 7, countOf7);
- QCOMPARE(countOf7, 0);
- }
-
- {
- int countOf3 = 0;
- ::qCount(list.begin(), list.end(), 3, countOf3);
- QCOMPARE(countOf3, 2);
- }
-
- {
- int countOf6 = 0;
- ::qCount(list.begin(), list.end(), 6, countOf6);
- QCOMPARE(countOf6, 3);
- }
-
- {
- int countOf8 = 0;
- ::qCount(list.begin(), list.end(), 8, countOf8);
- QCOMPARE(countOf8, 1);
- }
-
- /* Check that we add to the count, not set it. */
- {
- int countOf8 = 5;
- ::qCount(list.begin(), list.end(), 8, countOf8);
- QCOMPARE(countOf8, 6);
- }
-}
-
-void tst_QAlgorithms::qCountContainer() const
-{
- QList<int> list;
- list << 3 << 3 << 6 << 6 << 6 << 8;
-
- {
- int countOf7 = 0;
- ::qCount(list, 7, countOf7);
- QCOMPARE(countOf7, 0);
- }
-
- {
- int countOf3 = 0;
- ::qCount(list, 3, countOf3);
- QCOMPARE(countOf3, 2);
- }
-
- {
- int countOf6 = 0;
- ::qCount(list, 6, countOf6);
- QCOMPARE(countOf6, 3);
- }
-
- {
- int countOf8 = 0;
- ::qCount(list, 8, countOf8);
- QCOMPARE(countOf8, 1);
- }
-
- /* Check that we add to the count, not set it. */
- {
- int countOf8 = 5;
- ::qCount(list, 8, countOf8);
- QCOMPARE(countOf8, 6);
- }
-}
-
-class RAI
-{
- public:
- typedef int difference_type;
- typedef int value_type;
- typedef std::random_access_iterator_tag iterator_category;
- typedef int *pointer;
- typedef int &reference;
-
- RAI(int searched = 5, int hidePos = 4, int len = 10)
- : curPos_(0)
- , length_(len)
- , searchedVal_(searched)
- , searchedValPos_(hidePos)
- {
- }
-
- int at(int pos) const
- {
- if (pos == searchedValPos_) {
- return searchedVal_;
- }
- else if (pos < searchedValPos_) {
- return searchedVal_ - 1;
- }
-
- return searchedVal_ + 1;
- }
-
- RAI begin() const
- {
- RAI rai = *this;
- rai.setCurPos(0);
- return rai;
- }
-
- RAI end() const
- {
- RAI rai = *this;
- rai.setCurPos(length_);
- return rai;
- }
-
- int pos() const
- {
- return curPos();
- }
-
- int size() const
- {
- return length_;
- }
-
- RAI operator+(int i) const
- {
- RAI rai = *this;
- rai.setCurPos( rai.curPos() + i );
- if (rai.curPos() > length_) {
- rai.setCurPos(length_);
- }
- return rai;
- }
-
- RAI operator-(int i) const
- {
- RAI rai = *this;
- rai.setCurPos( rai.curPos() - i );
- if (rai.curPos() < 0) {
- rai.setCurPos(0);
- }
- return rai;
- }
-
- int operator-(const RAI& it) const
- {
- return curPos() - it.curPos();
- }
-
- RAI& operator+=(int i)
- {
- setCurPos( curPos() + i );
- if (curPos() > length_) {
- setCurPos(length_);
- }
- return *this;
- }
-
- RAI& operator-=(int i)
- {
- setCurPos( curPos() - i);
- if (curPos() < 0) {
- setCurPos(0);
- }
- return *this;
- }
-
- RAI& operator++()
- {
- if (curPos() < length_) {
- setCurPos( curPos() + 1 );
- }
- return *this;
- }
-
- RAI operator++(int)
- {
- RAI rai = *this;
-
- if (curPos() < length_) {
- setCurPos( curPos() + 1 );
- }
-
- return rai;
- }
-
- RAI& operator--()
- {
- if (curPos() > 0) {
- setCurPos( curPos() - 1 );
- }
- return *this;
- }
-
- RAI operator--(int)
- {
- RAI rai = *this;
-
- if (curPos() > 0) {
- setCurPos( curPos() - 1 );
- }
-
- return rai;
- }
-
- bool operator==(const RAI& rai) const
- {
- return rai.curPos() == curPos();
- }
-
- bool operator!=(const RAI& rai) const
- {
- return !operator==(rai);
- }
-
- int operator*() const
- {
- return at(curPos());
- }
-
- int operator[](int i) const
- {
- return at(i);
- }
-
- private:
-
- int curPos() const
- {
- return curPos_;
- }
-
- void setCurPos(int pos)
- {
- curPos_ = pos;
- }
-
- int curPos_;
- int length_;
- int searchedVal_;
- int searchedValPos_;
-};
-
-void tst_QAlgorithms::binaryFindOnLargeContainer() const
-{
- const int len = 2 * 1000 * 1000 * 537;
- const int pos = len - 12345;
- RAI rai(5, pos, len);
-
- RAI foundIt = qBinaryFind(rai.begin(), rai.end(), 5);
- QCOMPARE(foundIt.pos(), 1073987655);
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 2)
-
// alternative implementation of qPopulationCount for comparison:
-static Q_DECL_CONSTEXPR const uint bitsSetInNibble[] = {
+static constexpr const uint bitsSetInNibble[] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4,
};
-Q_STATIC_ASSERT(sizeof bitsSetInNibble / sizeof *bitsSetInNibble == 16);
+static_assert(sizeof bitsSetInNibble / sizeof *bitsSetInNibble == 16);
-static Q_DECL_CONSTEXPR uint bitsSetInByte(quint8 byte)
+static constexpr uint bitsSetInByte(quint8 byte)
{
return bitsSetInNibble[byte & 0xF] + bitsSetInNibble[byte >> 4];
}
-static Q_DECL_CONSTEXPR uint bitsSetInShort(quint16 word)
+static constexpr uint bitsSetInShort(quint16 word)
{
return bitsSetInByte(word & 0xFF) + bitsSetInByte(word >> 8);
}
-static Q_DECL_CONSTEXPR uint bitsSetInInt(quint32 word)
+static constexpr uint bitsSetInInt(quint32 word)
{
return bitsSetInShort(word & 0xFFFF) + bitsSetInShort(word >> 16);
}
-static Q_DECL_CONSTEXPR uint bitsSetInInt64(quint64 word)
+static constexpr uint bitsSetInInt64(quint64 word)
{
return bitsSetInInt(word & 0xFFFFFFFF) + bitsSetInInt(word >> 32);
}
@@ -1096,23 +261,26 @@ void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int)
const uint bits = bitsSetInByte(byte);
const quint64 value = static_cast<quint64>(byte);
const quint64 input = value << ((i % sizeof_T_Int) * 8U);
- QTest::addRow("0x%016llx", input) << input << bits;
+ QTest::addRow("%u-bits", i) << input << bits;
}
// and some random ones:
- if (sizeof_T_Int >= 8)
+ if (sizeof_T_Int >= 8) {
for (size_t i = 0; i < 1000; ++i) {
const quint64 input = QRandomGenerator::global()->generate64();
- QTest::addRow("0x%016llx", input) << input << bitsSetInInt64(input);
+ QTest::addRow("random-%zu", i) << input << bitsSetInInt64(input);
}
- else if (sizeof_T_Int >= 2)
- for (size_t i = 0; i < 1000 ; ++i) {
- const quint32 input = QRandomGenerator::global()->generate();
- if (sizeof_T_Int >= 4)
- QTest::addRow("0x%08x", input) << quint64(input) << bitsSetInInt(input);
- else
- QTest::addRow("0x%04x", quint16(input & 0xFFFF)) << quint64(input & 0xFFFF) << bitsSetInShort(input & 0xFFFF);
+ } else if (sizeof_T_Int >= 2) {
+ for (size_t i = 0; i < 1000 ; ++i) {
+ const quint32 input = QRandomGenerator::global()->generate();
+ if (sizeof_T_Int >= 4) {
+ QTest::addRow("random-%zu", i) << quint64(input) << bitsSetInInt(input);
+ } else {
+ QTest::addRow("random-%zu", i)
+ << quint64(input & 0xFFFF) << bitsSetInShort(input & 0xFFFF);
}
+ }
+ }
}
template <typename T_Int>
@@ -1122,22 +290,23 @@ void tst_QAlgorithms::popCount_impl()
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
-
+ PrintIfFailed pf(value);
QCOMPARE(qPopulationCount(value), expected);
}
+// Number of test-cases per offset into each size (arbitrary):
+static constexpr int casesPerOffset = 3;
+
void tst_QAlgorithms::countTrailing_data_impl(size_t sizeof_T_Int)
{
using namespace QTest;
addColumn<quint64>("input");
addColumn<uint>("expected");
- int nibs = sizeof_T_Int*2;
-
- newRow(("0x"+QByteArray::number(0,16).rightJustified(nibs,'0')).constData()) << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
+ addRow("0") << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 input = Q_UINT64_C(1) << i;
- newRow(("0x"+QByteArray::number(input,16).rightJustified(nibs,'0')).constData()) << input << i;
+ addRow("bit-%u", i) << input << i;
}
quint64 type_mask;
@@ -1148,12 +317,12 @@ 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 b = Q_UINT64_C(1) << i;
+ const quint64 mask = ((~(b - 1)) ^ b) & type_mask;
+ for (uint j = 0; j < sizeof_T_Int * casesPerOffset; ++j) {
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;
- newRow(("0x"+QByteArray::number(input,16).rightJustified(nibs,'0')).constData()) << input << i;
+ addRow("%u-bits-random-%u", i, j) << input << i;
}
}
}
@@ -1165,7 +334,7 @@ void tst_QAlgorithms::countTrailing_impl()
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
-
+ PrintIfFailed pf(value);
QCOMPARE(qCountTrailingZeroBits(value), expected);
}
@@ -1175,22 +344,20 @@ void tst_QAlgorithms::countLeading_data_impl(size_t sizeof_T_Int)
addColumn<quint64>("input");
addColumn<uint>("expected");
- int nibs = sizeof_T_Int*2;
-
- newRow(("0x"+QByteArray::number(0,16).rightJustified(nibs,'0')).constData()) << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
+ addRow("0") << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 input = Q_UINT64_C(1) << i;
- newRow(("0x"+QByteArray::number(input,16).rightJustified(nibs,'0')).constData()) << input << uint(sizeof_T_Int*8-i-1);
+ addRow("bit-%u", i) << input << uint(sizeof_T_Int*8-i-1);
}
// 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 b = Q_UINT64_C(1) << i;
+ const quint64 mask = b - 1;
+ for (uint j = 0; j < sizeof_T_Int * casesPerOffset; ++j) {
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;
- newRow(("0x"+QByteArray::number(input,16).rightJustified(nibs,'0')).constData()) << input << uint(sizeof_T_Int*8-i-1);
+ addRow("%u-bits-random-%u", i, j) << input << uint(sizeof_T_Int*8-i-1);
}
}
}
@@ -1202,7 +369,7 @@ void tst_QAlgorithms::countLeading_impl()
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
-
+ PrintIfFailed pf(value);
QCOMPARE(qCountLeadingZeroBits(value), expected);
}
diff --git a/tests/auto/corelib/tools/qarraydata/CMakeLists.txt b/tests/auto/corelib/tools/qarraydata/CMakeLists.txt
new file mode 100644
index 0000000000..1d84630de2
--- /dev/null
+++ b/tests/auto/corelib/tools/qarraydata/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qarraydata Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qarraydata LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qarraydata
+ EXCEPTIONS
+ SOURCES
+ simplevector.h
+ tst_qarraydata.cpp
+)
diff --git a/tests/auto/corelib/tools/qarraydata/qarraydata.pro b/tests/auto/corelib/tools/qarraydata/qarraydata.pro
deleted file mode 100644
index ee3faa9ad7..0000000000
--- a/tests/auto/corelib/tools/qarraydata/qarraydata.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-TARGET = tst_qarraydata
-SOURCES += $$PWD/tst_qarraydata.cpp
-HEADERS += $$PWD/simplevector.h
-QT = core testlib
-CONFIG += testcase
diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h
index 94cee5d887..b92cd4a887 100644
--- a/tests/auto/corelib/tools/qarraydata/simplevector.h
+++ b/tests/auto/corelib/tools/qarraydata/simplevector.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QARRAY_TEST_SIMPLE_VECTOR_H
@@ -32,6 +7,7 @@
#include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
+#include <QtCore/qvarlengtharray.h>
#include <algorithm>
@@ -40,46 +16,42 @@ struct SimpleVector
{
private:
typedef QTypedArrayData<T> Data;
+ typedef QArrayDataPointer<T> DataPointer;
public:
typedef T value_type;
- typedef typename Data::iterator iterator;
- typedef typename Data::const_iterator const_iterator;
+ typedef T *iterator;
+ typedef const T *const_iterator;
SimpleVector()
{
}
- explicit SimpleVector(size_t n)
- : d(Data::allocate(n))
+ explicit SimpleVector(size_t n, bool capacityReserved = false)
+ : d(n)
{
if (n)
d->appendInitialize(n);
+ if (capacityReserved)
+ d.setFlag(QArrayData::CapacityReserved);
}
- SimpleVector(size_t n, const T &t)
- : d(Data::allocate(n))
+ SimpleVector(size_t n, const T &t, bool capacityReserved = false)
+ : d(n)
{
if (n)
d->copyAppend(n, t);
+ if (capacityReserved)
+ d.setFlag(QArrayData::CapacityReserved);
}
- SimpleVector(const T *begin, const T *end)
- : d(Data::allocate(end - begin))
+ SimpleVector(const T *begin, const T *end, bool capacityReserved = false)
+ : d(end - begin)
{
if (end - begin)
d->copyAppend(begin, end);
- }
-
- SimpleVector(QArrayDataPointerRef<T> ptr)
- : d(ptr)
- {
- }
-
- template <size_t N>
- explicit SimpleVector(QStaticArrayData<T, N> &ptr)
- : d(static_cast<Data *>(&ptr.header), ptr.data, N)
- {
+ if (capacityReserved)
+ d.setFlag(QArrayData::CapacityReserved);
}
SimpleVector(Data *header, T *data, size_t len = 0)
@@ -87,8 +59,8 @@ public:
{
}
- explicit SimpleVector(QPair<Data*, T*> ptr, size_t len = 0)
- : d(ptr, len)
+ SimpleVector(const QArrayDataPointer<T> &other)
+ : d(other)
{
}
@@ -96,7 +68,7 @@ public:
bool isNull() const { return d.isNull(); }
bool isEmpty() const { return this->empty(); }
- bool isStatic() const { return d->isStatic(); }
+ bool isStatic() const { return !d.isMutable(); }
bool isShared() const { return d->isShared(); }
bool isSharedWith(const SimpleVector &other) const { return d == other.d; }
@@ -153,15 +125,16 @@ public:
if (d->flags() & Data::CapacityReserved)
return;
if (!d->isShared()) {
- d->flags() |= Data::CapacityReserved;
+ d.setFlag(Data::CapacityReserved);
return;
}
}
- SimpleVector detached(Data::allocate(qMax(n, size()),
- d->detachFlags() | Data::CapacityReserved));
- if (size())
+ SimpleVector detached(DataPointer(qMax(n, size())));
+ if (size()) {
detached.d->copyAppend(constBegin(), constEnd());
+ detached.d->setFlag(QArrayData::CapacityReserved);
+ }
detached.swap(*this);
}
@@ -171,8 +144,7 @@ public:
return;
if (d->needsDetach() || newSize > capacity()) {
- SimpleVector detached(Data::allocate(
- d->detachCapacity(newSize), d->detachFlags()));
+ SimpleVector detached(DataPointer(d->detachCapacity(newSize)));
if (newSize) {
if (newSize < size()) {
const T *const begin = constBegin();
@@ -205,46 +177,10 @@ public:
if (first == last)
return;
- T *const begin = d->begin();
- if (d->needsDetach()
- || capacity() - size() < size_t(last - first)) {
- SimpleVector detached(Data::allocate(
- d->detachCapacity(size() + (last - first)),
- d->detachFlags() | Data::GrowsForward));
-
- detached.d->copyAppend(first, last);
- detached.d->copyAppend(begin, begin + d->size);
- detached.swap(*this);
-
- return;
- }
-
- d->insert(begin, first, last);
+ d->insert(0, first, last - first);
}
- void append(const_iterator first, const_iterator last)
- {
- if (first == last)
- return;
-
- if (d->needsDetach()
- || capacity() - size() < size_t(last - first)) {
- SimpleVector detached(Data::allocate(
- d->detachCapacity(size() + (last - first)),
- d->detachFlags() | Data::GrowsForward));
-
- if (d->size) {
- const T *const begin = constBegin();
- detached.d->copyAppend(begin, begin + d->size);
- }
- detached.d->copyAppend(first, last);
- detached.swap(*this);
-
- return;
- }
-
- d->copyAppend(first, last);
- }
+ void append(const_iterator first, const_iterator last) { d->growAppend(first, last); }
void insert(int position, const_iterator first, const_iterator last)
{
@@ -264,37 +200,13 @@ public:
if (first == last)
return;
- const iterator begin = d->begin();
- const iterator where = begin + position;
- const iterator end = begin + d->size;
- if (d->needsDetach()
- || capacity() - size() < size_t(last - first)) {
- SimpleVector detached(Data::allocate(
- d->detachCapacity(size() + (last - first)),
- d->detachFlags() | Data::GrowsForward));
-
- if (position)
- detached.d->copyAppend(begin, where);
- detached.d->copyAppend(first, last);
- detached.d->copyAppend(where, end);
- detached.swap(*this);
-
- return;
- }
-
- if ((first >= where && first < end)
- || (last > where && last <= end)) {
- // Copy overlapping data first and only then shuffle it into place
- iterator start = d->begin() + position;
- iterator middle = d->end();
-
- d->copyAppend(first, last);
- std::rotate(start, middle, d->end());
-
+ if (first >= d.begin() && first <= d.end()) {
+ QVarLengthArray<T> copy(first, last);
+ insert(position, copy.begin(), copy.end());
return;
}
- d->insert(where, first, last);
+ d->insert(position, first, last - first);
}
void erase(iterator first, iterator last)
@@ -306,9 +218,7 @@ public:
const T *const end = begin + d->size;
if (d->needsDetach()) {
- SimpleVector detached(Data::allocate(
- d->detachCapacity(size() - (last - first)),
- d->detachFlags()));
+ SimpleVector detached(DataPointer(d->detachCapacity(size() - (last - first))));
if (first != begin)
detached.d->copyAppend(begin, first);
detached.d->copyAppend(last, end);
@@ -320,7 +230,7 @@ public:
if (last == end)
d->truncate(end - first);
else
- d->erase(first, last);
+ d->erase(first, last - first);
}
void swap(SimpleVector &other)
@@ -338,10 +248,9 @@ public:
d.detach();
}
- static SimpleVector fromRawData(const T *data, size_t size,
- QArrayData::ArrayOptions options = Data::DefaultRawFlags)
+ static SimpleVector fromRawData(const T *data, size_t size)
{
- return SimpleVector(Data::fromRawData(data, size, options));
+ return SimpleVector(QArrayDataPointer<T>::fromRawData(data, size));
}
private:
diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
index 1366eebf97..e7a84d57ee 100644
--- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
+++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp
@@ -1,53 +1,30 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-
-#include <QtTest/QtTest>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
+#include <QTest>
#include <QtCore/QString>
#include <QtCore/qarraydata.h>
#include "simplevector.h"
-struct SharedNullVerifier
-{
- SharedNullVerifier()
- {
- Q_ASSERT(QArrayData::shared_null[0].isStatic());
- Q_ASSERT(QArrayData::shared_null[0].isShared());
- }
-};
-
-// This is meant to verify/ensure that shared_null is not being dynamically
-// initialized and stays away from the order-of-static-initialization fiasco.
-//
-// Of course, if this was to fail, qmake and the build should have crashed and
-// burned before we ever got to this point :-)
-SharedNullVerifier globalInit;
+#include <array>
+#include <tuple>
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <stdexcept>
+#include <functional>
+#include <memory>
+
+// A wrapper for a test function. Calls a function, if it fails, reports failure
+#define RUN_TEST_FUNC(test, ...) \
+do { \
+ test(__VA_ARGS__); \
+ if (QTest::currentTestFailed()) \
+ QFAIL("Test case " #test "(" #__VA_ARGS__ ") failed"); \
+} while (false)
class tst_QArrayData : public QObject
{
@@ -55,7 +32,6 @@ class tst_QArrayData : public QObject
private slots:
void referenceCounting();
- void sharedNullEmpty();
void simpleVector();
void simpleVectorReserve_data();
void simpleVectorReserve();
@@ -67,14 +43,28 @@ private slots:
void alignment();
void typedData();
void gccBug43247();
+ void arrayOps_data();
void arrayOps();
+ void arrayOps2_data();
void arrayOps2();
+ void arrayOpsExtra_data();
+ void arrayOpsExtra();
void fromRawData_data();
void fromRawData();
void literals();
void variadicLiterals();
void rValueReferences();
void grow();
+ void freeSpace_data();
+ void freeSpace();
+ void dataPointerAllocate_data();
+ void dataPointerAllocate();
+ void selfEmplaceBackwards();
+ void selfEmplaceForward();
+#ifndef QT_NO_EXCEPTIONS
+ void relocateWithExceptions_data();
+ void relocateWithExceptions();
+#endif // QT_NO_EXCEPTIONS
};
template <class T> const T &const_(const T &t) { return t; }
@@ -83,12 +73,10 @@ void tst_QArrayData::referenceCounting()
{
{
// Reference counting initialized to 1 (owned)
- QArrayData array = { Q_BASIC_ATOMIC_INITIALIZER(1), QArrayData::DefaultRawFlags, 0 };
+ QArrayData array = { Q_BASIC_ATOMIC_INITIALIZER(1), {}, 0 };
QCOMPARE(array.ref_.loadRelaxed(), 1);
- QVERIFY(!array.isStatic());
-
QVERIFY(array.ref());
QCOMPARE(array.ref_.loadRelaxed(), 2);
@@ -106,72 +94,21 @@ void tst_QArrayData::referenceCounting()
// Now would be a good time to free/release allocated data
}
- {
- // Reference counting initialized to -1 (static read-only data)
- QArrayData array = { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 };
-
- QCOMPARE(array.ref_.loadRelaxed(), -1);
-
- QVERIFY(array.isStatic());
-
- QVERIFY(array.ref());
- QCOMPARE(array.ref_.loadRelaxed(), -1);
-
- QVERIFY(array.deref());
- QCOMPARE(array.ref_.loadRelaxed(), -1);
-
- }
-}
-
-void tst_QArrayData::sharedNullEmpty()
-{
- QArrayData *null = const_cast<QArrayData *>(QArrayData::shared_null);
- QArrayData *empty;
- QArrayData::allocate(&empty, 1, alignof(QArrayData), 0);
-
- QVERIFY(null->isStatic());
- QVERIFY(null->isShared());
-
- QVERIFY(empty->isStatic());
- QVERIFY(empty->isShared());
-
- QCOMPARE(null->ref_.loadRelaxed(), -1);
- QCOMPARE(empty->ref_.loadRelaxed(), -1);
-
- QCOMPARE(null->ref_.loadRelaxed(), -1);
- QCOMPARE(empty->ref_.loadRelaxed(), -1);
-
- QVERIFY(null->deref());
- QVERIFY(empty->deref());
-
- QCOMPARE(null->ref_.loadRelaxed(), -1);
- QCOMPARE(empty->ref_.loadRelaxed(), -1);
-
- QVERIFY(null != empty);
-
- QCOMPARE(null->allocatedCapacity(), size_t(0));
-
- QCOMPARE(empty->allocatedCapacity(), size_t(0));
}
void tst_QArrayData::simpleVector()
{
- QArrayData data0 = { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 };
- QStaticArrayData<int, 7> data1 = {
- { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 },
- { 0, 1, 2, 3, 4, 5, 6 }
- };
-
+ int data[] = { 0, 1, 2, 3, 4, 5, 6 };
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
SimpleVector<int> v1;
SimpleVector<int> v2(v1);
- SimpleVector<int> v3(static_cast<QTypedArrayData<int> *>(&data0), 0, 0);
- SimpleVector<int> v4(data1);
- SimpleVector<int> v5(static_cast<QTypedArrayData<int> *>(&data0), 0, 0);
- SimpleVector<int> v6(data1);
- SimpleVector<int> v7(10, 5);
- SimpleVector<int> v8(array, array + sizeof(array)/sizeof(*array));
+ SimpleVector<int> v3(nullptr, (int *)nullptr, 0);
+ SimpleVector<int> v4(nullptr, data, 0);
+ SimpleVector<int> v5(nullptr, data, 1);
+ SimpleVector<int> v6(nullptr, data, 7);
+ const SimpleVector<int> v7(10, 5);
+ const SimpleVector<int> v8(array, array + sizeof(array)/sizeof(*array));
v3 = v1;
v1.swap(v3);
@@ -190,7 +127,7 @@ void tst_QArrayData::simpleVector()
QVERIFY(v2.isEmpty());
QVERIFY(v3.isEmpty());
QVERIFY(v4.isEmpty());
- QVERIFY(v5.isEmpty());
+ QVERIFY(!v5.isEmpty());
QVERIFY(!v6.isEmpty());
QVERIFY(!v7.isEmpty());
QVERIFY(!v8.isEmpty());
@@ -199,7 +136,7 @@ void tst_QArrayData::simpleVector()
QCOMPARE(v2.size(), size_t(0));
QCOMPARE(v3.size(), size_t(0));
QCOMPARE(v4.size(), size_t(0));
- QCOMPARE(v5.size(), size_t(0));
+ QCOMPARE(v5.size(), size_t(1));
QCOMPARE(v6.size(), size_t(7));
QCOMPARE(v7.size(), size_t(10));
QCOMPARE(v8.size(), size_t(10));
@@ -248,13 +185,13 @@ void tst_QArrayData::simpleVector()
QVERIFY(v1 == v2);
QVERIFY(v1 == v3);
QVERIFY(v1 == v4);
- QVERIFY(v1 == v5);
+ QVERIFY(v1 != v5);
QVERIFY(!(v1 == v6));
QVERIFY(v1 != v6);
QVERIFY(v4 != v6);
QVERIFY(v5 != v6);
- QVERIFY(!(v1 != v5));
+ QVERIFY(!(v1 == v5));
QVERIFY(v1 < v6);
QVERIFY(!(v6 < v1));
@@ -299,7 +236,7 @@ void tst_QArrayData::simpleVector()
{
int count = 0;
- Q_FOREACH (int value, v7) {
+ for (int value : v7) {
QCOMPARE(value, 5);
++count;
}
@@ -309,7 +246,7 @@ void tst_QArrayData::simpleVector()
{
int count = 0;
- Q_FOREACH (int value, v8) {
+ for (int value : v8) {
QCOMPARE(value, count);
++count;
}
@@ -428,17 +365,10 @@ void tst_QArrayData::simpleVectorReserve_data()
QTest::newRow("empty") << SimpleVector<int>(0, 42) << size_t(0) << size_t(0);
QTest::newRow("non-empty") << SimpleVector<int>(5, 42) << size_t(5) << size_t(5);
- static const QStaticArrayData<int, 15> array = {
- { Q_BASIC_ATOMIC_INITIALIZER(-1), QArrayData::StaticDataFlags, 0 },
- { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } };
- const QArrayDataPointerRef<int> p = {
- static_cast<QTypedArrayData<int> *>(
- const_cast<QArrayData *>(&array.header)),
- const_cast<int *>(array.data),
- sizeof(array.data) / sizeof(array.data[0]) };
-
- QTest::newRow("static") << SimpleVector<int>(p) << size_t(0) << size_t(15);
- QTest::newRow("raw-data") << SimpleVector<int>::fromRawData(array.data, 15) << size_t(0) << size_t(15);
+ static const int array[] =
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+ QTest::newRow("raw-data") << SimpleVector<int>::fromRawData(array, 15) << size_t(0) << size_t(15);
}
void tst_QArrayData::simpleVectorReserve()
@@ -494,7 +424,7 @@ struct Deallocator
size_t objectSize;
size_t alignment;
- QVector<QArrayData *> headers;
+ QList<QArrayData *> headers;
};
Q_DECLARE_METATYPE(const QArrayData *)
@@ -504,9 +434,7 @@ void tst_QArrayData::allocate_data()
{
QTest::addColumn<size_t>("objectSize");
QTest::addColumn<size_t>("alignment");
- QTest::addColumn<QArrayData::ArrayOptions>("allocateOptions");
- QTest::addColumn<bool>("isCapacityReserved");
- QTest::addColumn<const QArrayData *>("commonEmpty");
+ QTest::addColumn<bool>("grow");
struct {
char const *typeName;
@@ -518,19 +446,12 @@ void tst_QArrayData::allocate_data()
{ "void *", sizeof(void *), alignof(void *) }
};
- QArrayData *shared_empty;
- QArrayData::allocate(&shared_empty, 1, alignof(QArrayData), 0);
- QVERIFY(shared_empty);
-
struct {
char const *description;
- QArrayData::ArrayOptions allocateOptions;
- bool isCapacityReserved;
- const QArrayData *commonEmpty;
+ bool grow;
} options[] = {
- { "Default", QArrayData::DefaultAllocationFlags, false, shared_empty },
- { "Reserved", QArrayData::CapacityReserved, true, shared_empty },
- { "Grow", QArrayData::GrowsForward, false, shared_empty }
+ { "Default", false },
+ { "Grow", true }
};
for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i)
@@ -540,42 +461,32 @@ void tst_QArrayData::allocate_data()
+ QLatin1String(": ")
+ QLatin1String(options[j].description)))
<< types[i].objectSize << types[i].alignment
- << options[j].allocateOptions << options[j].isCapacityReserved
- << options[j].commonEmpty;
+ << options[j].grow;
}
void tst_QArrayData::allocate()
{
QFETCH(size_t, objectSize);
QFETCH(size_t, alignment);
- QFETCH(QArrayData::ArrayOptions, allocateOptions);
- QFETCH(bool, isCapacityReserved);
- QFETCH(const QArrayData *, commonEmpty);
+ QFETCH(bool, grow);
// Minimum alignment that can be requested is that of QArrayData.
// Typically, this alignment is sizeof(void *) and ensured by malloc.
size_t minAlignment = qMax(alignment, alignof(QArrayData));
- // Shared Empty
- QArrayData *empty;
- QCOMPARE((QArrayData::allocate(&empty, objectSize, minAlignment, 0,
- QArrayData::ArrayOptions(allocateOptions)), empty), commonEmpty);
-
Deallocator keeper(objectSize, minAlignment);
keeper.headers.reserve(1024);
- for (int capacity = 1; capacity <= 1024; capacity <<= 1) {
+ for (qsizetype capacity = 1; capacity <= 1024; capacity <<= 1) {
QArrayData *data;
- void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment,
- capacity, QArrayData::ArrayOptions(allocateOptions));
+ void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, grow ? QArrayData::Grow : QArrayData::KeepSize);
keeper.headers.append(data);
- if (allocateOptions & QArrayData::GrowsForward)
- QVERIFY(data->allocatedCapacity() > uint(capacity));
+ if (grow)
+ QCOMPARE_GE(data->allocatedCapacity(), capacity);
else
- QCOMPARE(data->allocatedCapacity(), size_t(capacity));
- QCOMPARE(bool(data->flags & QArrayData::CapacityReserved), isCapacityReserved);
+ QCOMPARE(data->allocatedCapacity(), capacity);
// Check that the allocated array can be used. Best tested with a
// memory checker, such as valgrind, running.
@@ -587,8 +498,7 @@ void tst_QArrayData::reallocate()
{
QFETCH(size_t, objectSize);
QFETCH(size_t, alignment);
- QFETCH(QArrayData::ArrayOptions, allocateOptions);
- QFETCH(bool, isCapacityReserved);
+ QFETCH(bool, grow);
// Minimum alignment that can be requested is that of QArrayData.
// Typically, this alignment is sizeof(void *) and ensured by malloc.
@@ -597,27 +507,24 @@ void tst_QArrayData::reallocate()
int capacity = 10;
Deallocator keeper(objectSize, minAlignment);
QArrayData *data;
- void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity,
- QArrayData::ArrayOptions(allocateOptions) & ~QArrayData::GrowsForward);
+ void *dataPointer = QArrayData::allocate(&data, objectSize, minAlignment, capacity, grow ? QArrayData::Grow : QArrayData::KeepSize);
keeper.headers.append(data);
memset(dataPointer, 'A', objectSize * capacity);
// now try to reallocate
int newCapacity = 40;
- auto pair = QArrayData::reallocateUnaligned(data, dataPointer, objectSize, newCapacity,
- QArrayData::ArrayOptions(allocateOptions));
+ auto pair = QArrayData::reallocateUnaligned(data, dataPointer, objectSize, newCapacity, grow ? QArrayData::Grow : QArrayData::KeepSize);
data = pair.first;
dataPointer = pair.second;
QVERIFY(data);
keeper.headers.clear();
keeper.headers.append(data);
- if (allocateOptions & QArrayData::GrowsForward)
- QVERIFY(data->allocatedCapacity() > size_t(newCapacity));
+ if (grow)
+ QVERIFY(data->allocatedCapacity() > newCapacity);
else
- QCOMPARE(data->allocatedCapacity(), size_t(newCapacity));
- QCOMPARE(!(data->flags & QArrayData::CapacityReserved), !isCapacityReserved);
+ QCOMPARE(data->allocatedCapacity(), newCapacity);
for (int i = 0; i < capacity; ++i)
QCOMPARE(static_cast<char *>(dataPointer)[i], 'A');
@@ -625,7 +532,7 @@ void tst_QArrayData::reallocate()
class Unaligned
{
- char dummy[8];
+ Q_DECL_UNUSED_MEMBER char dummy[8];
};
void tst_QArrayData::alignment_data()
@@ -651,8 +558,7 @@ void tst_QArrayData::alignment()
for (int i = 0; i < 100; ++i) {
QArrayData *data;
- void *dataPointer = QArrayData::allocate(&data, sizeof(Unaligned),
- minAlignment, 8, QArrayData::DefaultAllocationFlags);
+ void *dataPointer = QArrayData::allocate(&data, sizeof(Unaligned), minAlignment, 8, QArrayData::KeepSize);
keeper.headers.append(data);
QVERIFY(data);
@@ -685,7 +591,7 @@ void tst_QArrayData::typedData()
keeper.headers.append(array);
QVERIFY(array);
- QCOMPARE(array->allocatedCapacity(), size_t(10));
+ QCOMPARE(array->allocatedCapacity(), qsizetype(10));
// Check that the allocated array can be used. Best tested with a
// memory checker, such as valgrind, running.
@@ -705,7 +611,7 @@ void tst_QArrayData::typedData()
keeper.headers.append(array);
QVERIFY(array);
- QCOMPARE(array->allocatedCapacity(), size_t(10));
+ QCOMPARE(array->allocatedCapacity(), qsizetype(10));
// Check that the allocated array can be used. Best tested with a
// memory checker, such as valgrind, running.
@@ -725,7 +631,7 @@ void tst_QArrayData::typedData()
keeper.headers.append(array);
QVERIFY(array);
- QCOMPARE(array->allocatedCapacity(), size_t(10));
+ QCOMPARE(array->allocatedCapacity(), qsizetype(10));
// Check that the allocated array can be used. Best tested with a
// memory checker, such as valgrind, running.
@@ -742,7 +648,7 @@ void tst_QArrayData::gccBug43247()
{
// This test tries to verify QArrayData is not affected by GCC optimizer
// bug #43247.
- // Reported on GCC 4.4.3, Linux, affects QVector
+ // Reported on GCC 4.4.3, Linux, affects QList
QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (3)");
QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (4)");
@@ -751,7 +657,7 @@ void tst_QArrayData::gccBug43247()
QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (7)");
SimpleVector<int> array(10, 0);
- // QVector<int> vector(10, 0);
+ // QList<int> list(10, 0);
for (int i = 0; i < 10; ++i) {
if (i >= 3 && i < 8)
@@ -761,7 +667,7 @@ void tst_QArrayData::gccBug43247()
// line lets the compiler assume i == 0, and the conditional above is
// skipped.
QVERIFY(array.at(i) == 0);
- // QVERIFY(vector.at(i) == 0);
+ // QVERIFY(list.at(i) == 0);
}
}
@@ -822,11 +728,25 @@ struct CountedObject
static size_t liveCount;
};
+bool operator==(const CountedObject &lhs, const CountedObject &rhs)
+{
+ return lhs.id == rhs.id; // TODO: anything better than this?
+}
+
size_t CountedObject::liveCount = 0;
+void tst_QArrayData::arrayOps_data()
+{
+ QTest::addColumn<bool>("capacityReserved");
+
+ QTest::newRow("default") << false;
+ QTest::newRow("capacity-reserved") << true;
+}
+
void tst_QArrayData::arrayOps()
{
- CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker)
+ QFETCH(bool, capacityReserved);
+ CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker);
const int intArray[5] = { 80, 101, 100, 114, 111 };
const QString stringArray[5] = {
@@ -838,9 +758,12 @@ void tst_QArrayData::arrayOps()
};
const CountedObject objArray[5];
- QVERIFY(!QTypeInfo<int>::isComplex && !QTypeInfo<int>::isStatic);
- QVERIFY(QTypeInfo<QString>::isComplex && !QTypeInfo<QString>::isStatic);
- QVERIFY(QTypeInfo<CountedObject>::isComplex && QTypeInfo<CountedObject>::isStatic);
+ static_assert(!QTypeInfo<int>::isComplex);
+ static_assert(QTypeInfo<int>::isRelocatable);
+ static_assert(QTypeInfo<QString>::isComplex);
+ static_assert(QTypeInfo<QString>::isRelocatable);
+ static_assert(QTypeInfo<CountedObject>::isComplex);
+ static_assert(!QTypeInfo<CountedObject>::isRelocatable);
QCOMPARE(CountedObject::liveCount, size_t(5));
for (size_t i = 0; i < 5; ++i)
@@ -848,9 +771,9 @@ void tst_QArrayData::arrayOps()
////////////////////////////////////////////////////////////////////////////
// copyAppend (I)
- SimpleVector<int> vi(intArray, intArray + 5);
- SimpleVector<QString> vs(stringArray, stringArray + 5);
- SimpleVector<CountedObject> vo(objArray, objArray + 5);
+ SimpleVector<int> vi(intArray, intArray + 5, capacityReserved);
+ SimpleVector<QString> vs(stringArray, stringArray + 5, capacityReserved);
+ SimpleVector<CountedObject> vo(objArray, objArray + 5, capacityReserved);
QCOMPARE(CountedObject::liveCount, size_t(10));
for (int i = 0; i < 5; ++i) {
@@ -876,9 +799,9 @@ void tst_QArrayData::arrayOps()
QString referenceString = QLatin1String("reference");
CountedObject referenceObject;
- vi = SimpleVector<int>(5, referenceInt);
- vs = SimpleVector<QString>(5, referenceString);
- vo = SimpleVector<CountedObject>(5, referenceObject);
+ vi = SimpleVector<int>(5, referenceInt, capacityReserved);
+ vs = SimpleVector<QString>(5, referenceString, capacityReserved);
+ vo = SimpleVector<CountedObject>(5, referenceObject, capacityReserved);
QCOMPARE(vi.size(), size_t(5));
QCOMPARE(vs.size(), size_t(5));
@@ -890,8 +813,11 @@ void tst_QArrayData::arrayOps()
QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id);
- QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
- | CountedObject::DefaultConstructed);
+
+ // A temporary object is created as DefaultConstructed |
+ // CopyConstructed, then it is used instead of the original value to
+ // construct elements in the container which are CopyConstructed only
+ //QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed);
}
////////////////////////////////////////////////////////////////////////////
@@ -941,8 +867,14 @@ void tst_QArrayData::arrayOps()
QVERIFY(vs[i].isSharedWith(stringArray[i % 5]));
QCOMPARE(vo[i].id, objArray[i % 5].id);
- QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed
- | CountedObject::CopyAssigned);
+
+ // Insertion at begin (prepend) caused the elements to move, meaning
+ // that instead of being displaced, newly added elements got constructed
+ // in uninitialized memory with DefaultConstructed | CopyConstructed
+ // ### QArrayData::insert does copy assign some of the values, so this test doesn't
+ // work
+// QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed
+// | CountedObject::CopyConstructed);
}
for (int i = 5; i < 15; ++i) {
@@ -950,8 +882,8 @@ void tst_QArrayData::arrayOps()
QVERIFY(vs[i].isSharedWith(stringArray[i % 5]));
QCOMPARE(vo[i].id, objArray[i % 5].id);
- QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
- | CountedObject::CopyAssigned);
+// QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
+// | CountedObject::CopyAssigned);
}
for (int i = 15; i < 20; ++i) {
@@ -959,8 +891,8 @@ void tst_QArrayData::arrayOps()
QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id);
- QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
- | CountedObject::CopyAssigned);
+// QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
+// | CountedObject::CopyAssigned);
}
for (int i = 20; i < 25; ++i) {
@@ -975,8 +907,8 @@ void tst_QArrayData::arrayOps()
// Depending on implementation of rotate, final assignment can be:
// - straight from source: DefaultConstructed | CopyAssigned
// - through a temporary: CopyConstructed | CopyAssigned
- QCOMPARE(vo[i].flags & CountedObject::CopyAssigned,
- int(CountedObject::CopyAssigned));
+// QCOMPARE(vo[i].flags & CountedObject::CopyAssigned,
+// int(CountedObject::CopyAssigned));
}
for (int i = 25; i < 30; ++i) {
@@ -984,20 +916,26 @@ void tst_QArrayData::arrayOps()
QVERIFY(vs[i].isSharedWith(referenceString));
QCOMPARE(vo[i].id, referenceObject.id);
- QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
- | CountedObject::CopyAssigned);
+// QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed
+// | CountedObject::CopyAssigned);
}
}
+void tst_QArrayData::arrayOps2_data()
+{
+ arrayOps_data();
+}
+
void tst_QArrayData::arrayOps2()
{
- CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker)
+ QFETCH(bool, capacityReserved);
+ CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker);
////////////////////////////////////////////////////////////////////////////
// appendInitialize
- SimpleVector<int> vi(5);
- SimpleVector<QString> vs(5);
- SimpleVector<CountedObject> vo(5);
+ SimpleVector<int> vi(5, capacityReserved);
+ SimpleVector<QString> vs(5, capacityReserved);
+ SimpleVector<CountedObject> vo(5, capacityReserved);
QCOMPARE(vi.size(), size_t(5));
QCOMPARE(vs.size(), size_t(5));
@@ -1106,6 +1044,8 @@ void tst_QArrayData::arrayOps2()
QVERIFY(vs[i].isNull());
QCOMPARE(vo[i].id, i);
+ // Erasing not from begin always shifts left - consistency with
+ // std::vector::erase. Elements before erase position are not affected.
QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed
| CountedObject::CopyConstructed);
}
@@ -1129,24 +1069,631 @@ void tst_QArrayData::arrayOps2()
}
}
-Q_DECLARE_METATYPE(QArrayDataPointer<int>)
+void tst_QArrayData::arrayOpsExtra_data()
+{
+ dataPointerAllocate_data();
+}
-static inline bool arrayIsFilledWith(const QArrayDataPointer<int> &array,
- int fillValue, size_t size)
+void tst_QArrayData::arrayOpsExtra()
{
- const int *iter = array->begin();
- const int *const end = array->end();
+ QSKIP("Skipped while changing QArrayData operations.", SkipAll);
+ QFETCH(QArrayData::GrowthPosition, GrowthPosition);
+ CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker);
+
+ constexpr size_t inputSize = 5;
+ const std::array<int, inputSize> intArray = { 80, 101, 100, 114, 111 };
+ const std::array<QString, inputSize> stringArray = {
+ QLatin1String("just"), QLatin1String("for"), QLatin1String("testing"), QLatin1String("a"),
+ QLatin1String("vector")
+ };
+ const std::array<CountedObject, inputSize> objArray;
+
+ QVERIFY(!QTypeInfo<int>::isComplex && QTypeInfo<int>::isRelocatable);
+ QVERIFY(QTypeInfo<QString>::isComplex && QTypeInfo<QString>::isRelocatable);
+ QVERIFY(QTypeInfo<CountedObject>::isComplex && !QTypeInfo<CountedObject>::isRelocatable);
+
+ QCOMPARE(CountedObject::liveCount, inputSize);
+ for (size_t i = 0; i < 5; ++i)
+ QCOMPARE(objArray[i].id, i);
+
+ const auto setupDataPointers = [&GrowthPosition] (size_t capacity, size_t initialSize = 0) {
+ const qsizetype alloc = qsizetype(capacity);
+ auto i = QArrayDataPointer<int>::allocateGrow(QArrayDataPointer<int>(), alloc, GrowthPosition);
+ auto s = QArrayDataPointer<QString>::allocateGrow(QArrayDataPointer<QString>(), alloc, GrowthPosition);
+ auto o = QArrayDataPointer<CountedObject>::allocateGrow(QArrayDataPointer<CountedObject>(), alloc, GrowthPosition);
+ if (initialSize) {
+ i->appendInitialize(initialSize);
+ s->appendInitialize(initialSize);
+ o->appendInitialize(initialSize);
+ }
+
+ // assign unique values
+ std::generate(i.begin(), i.end(), [] () { static int i = 0; return i++; });
+ std::generate(s.begin(), s.end(), [] () { static int i = 0; return QString::number(i++); });
+ std::generate(o.begin(), o.end(), [] () { return CountedObject(); });
+ return std::make_tuple(i, s, o);
+ };
+
+ const auto cloneArrayDataPointer = [] (auto &dataPointer, size_t capacity) {
+ using ArrayPointer = std::decay_t<decltype(dataPointer)>;
+ ArrayPointer copy{qsizetype(capacity)};
+ copy->copyAppend(dataPointer.begin(), dataPointer.end());
+ return copy;
+ };
+
+ // Test allocation first
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ auto [intData, strData, objData] = setupDataPointers(inputSize);
+ QVERIFY(intData.size == 0);
+ QVERIFY(intData.d_ptr() != nullptr);
+ QVERIFY(size_t(intData.constAllocatedCapacity()) >= inputSize);
+ QVERIFY(intData.data() != nullptr);
+
+ QVERIFY(strData.size == 0);
+ QVERIFY(strData.d_ptr() != nullptr);
+ QVERIFY(size_t(strData.constAllocatedCapacity()) >= inputSize);
+ QVERIFY(strData.data() != nullptr);
+
+ QVERIFY(objData.size == 0);
+ QVERIFY(objData.d_ptr() != nullptr);
+ QVERIFY(size_t(objData.constAllocatedCapacity()) >= inputSize);
+ QVERIFY(objData.data() != nullptr);
+ }
+
+ // copyAppend (iterator version)
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testCopyAppend = [&] (auto &dataPointer, auto first, auto last) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ const size_t distance = std::distance(first, last);
+
+ dataPointer->appendIteratorRange(first, last);
+ QCOMPARE(size_t(dataPointer.size), originalSize + distance);
+ size_t i = 0;
+ for (; i < originalSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], *(first + (i - originalSize)));
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // empty range
+ const std::array<int, 0> emptyIntArray{};
+ const std::array<QString, 0> emptyStrArray{};
+ const std::array<CountedObject, 0> emptyObjArray{};
+ RUN_TEST_FUNC(testCopyAppend, intData, emptyIntArray.begin(), emptyIntArray.end());
+ RUN_TEST_FUNC(testCopyAppend, strData, emptyStrArray.begin(), emptyStrArray.end());
+ RUN_TEST_FUNC(testCopyAppend, objData, emptyObjArray.begin(), emptyObjArray.end());
+
+ // from arbitrary iterators
+ RUN_TEST_FUNC(testCopyAppend, intData, intArray.begin(), intArray.end());
+ RUN_TEST_FUNC(testCopyAppend, strData, stringArray.begin(), stringArray.end());
+ RUN_TEST_FUNC(testCopyAppend, objData, objArray.begin(), objArray.end());
+
+ // append to full
+ const size_t intDataFreeSpace = intData.freeSpaceAtEnd();
+// QVERIFY(intDataFreeSpace > 0);
+ const size_t strDataFreeSpace = strData.freeSpaceAtEnd();
+// QVERIFY(strDataFreeSpace > 0);
+ const size_t objDataFreeSpace = objData.freeSpaceAtEnd();
+// QVERIFY(objDataFreeSpace > 0);
+ const std::vector<int> intVec(intDataFreeSpace, int(55));
+ const std::vector<QString> strVec(strDataFreeSpace, QLatin1String("filler"));
+ const std::vector<CountedObject> objVec(objDataFreeSpace, CountedObject());
+ RUN_TEST_FUNC(testCopyAppend, intData, intVec.begin(), intVec.end());
+ RUN_TEST_FUNC(testCopyAppend, strData, strVec.begin(), strVec.end());
+ RUN_TEST_FUNC(testCopyAppend, objData, objVec.begin(), objVec.end());
+ QCOMPARE(intData.size, intData.constAllocatedCapacity() - intData.freeSpaceAtBegin());
+ QCOMPARE(strData.size, strData.constAllocatedCapacity() - strData.freeSpaceAtBegin());
+ QCOMPARE(objData.size, objData.constAllocatedCapacity() - objData.freeSpaceAtBegin());
+ }
+
+ // copyAppend (iterator version) - special case of copying from self iterators
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testCopyAppendSelf = [&] (auto &dataPointer, auto first, auto last) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ const size_t distance = std::distance(first, last);
+ auto firstCopy = copy->begin() + std::distance(dataPointer->begin(), first);
+
+ dataPointer->copyAppend(first, last);
+ QCOMPARE(size_t(dataPointer.size), originalSize + distance);
+ size_t i = 0;
+ for (; i < originalSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], *(firstCopy + (i - originalSize)));
+ };
- for (size_t i = 0; i < size; ++i, ++iter)
- if (*iter != fillValue)
- return false;
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // make no free space at the end
+ intData->appendInitialize(intData.size + intData.freeSpaceAtEnd());
+ strData->appendInitialize(strData.size + strData.freeSpaceAtEnd());
+ objData->appendInitialize(objData.size + objData.freeSpaceAtEnd());
+
+ // make all values unique. this would ensure that we do not have erroneously passed test
+ int i = 0;
+ std::generate(intData.begin(), intData.end(), [&i] () { return i++; });
+ std::generate(strData.begin(), strData.end(), [&i] () { return QString::number(i++); });
+ std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); });
+
+ // sanity checks:
+ if (GrowthPosition & QArrayData::GrowsAtBeginning) {
+ QVERIFY(intData.freeSpaceAtBegin() > 0);
+ QVERIFY(strData.freeSpaceAtBegin() > 0);
+ QVERIFY(objData.freeSpaceAtBegin() > 0);
+ }
+ QVERIFY(intData.freeSpaceAtBegin() <= intData.size);
+ QVERIFY(strData.freeSpaceAtBegin() <= strData.size);
+ QVERIFY(objData.freeSpaceAtBegin() <= objData.size);
+ QVERIFY(intData.freeSpaceAtEnd() == 0);
+ QVERIFY(strData.freeSpaceAtEnd() == 0);
+ QVERIFY(objData.freeSpaceAtEnd() == 0);
+
+ // now, append to full size causing the data to move internally. passed
+ // iterators that refer to the object itself must be used correctly
+ RUN_TEST_FUNC(testCopyAppendSelf, intData, intData.begin(),
+ intData.begin() + intData.freeSpaceAtBegin());
+ RUN_TEST_FUNC(testCopyAppendSelf, strData, strData.begin(),
+ strData.begin() + strData.freeSpaceAtBegin());
+ RUN_TEST_FUNC(testCopyAppendSelf, objData, objData.begin(),
+ objData.begin() + objData.freeSpaceAtBegin());
+ }
- if (iter != end)
- return false;
+ // copyAppend (value version)
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testCopyAppend = [&] (auto &dataPointer, size_t n, auto value) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->copyAppend(n, value);
+ QCOMPARE(size_t(dataPointer.size), originalSize + n);
+ size_t i = 0;
+ for (; i < originalSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], value);
+ };
- return true;
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // no values
+ RUN_TEST_FUNC(testCopyAppend, intData, 0, int());
+ RUN_TEST_FUNC(testCopyAppend, strData, 0, QString());
+ RUN_TEST_FUNC(testCopyAppend, objData, 0, CountedObject());
+
+ // several values
+ RUN_TEST_FUNC(testCopyAppend, intData, inputSize, int(5));
+ RUN_TEST_FUNC(testCopyAppend, strData, inputSize, QLatin1String("42"));
+ RUN_TEST_FUNC(testCopyAppend, objData, inputSize, CountedObject());
+
+ // from self
+ RUN_TEST_FUNC(testCopyAppend, intData, 2, intData.data()[3]);
+ RUN_TEST_FUNC(testCopyAppend, strData, 2, strData.data()[3]);
+ RUN_TEST_FUNC(testCopyAppend, objData, 2, objData.data()[3]);
+
+ // append to full
+ const size_t intDataFreeSpace = intData.constAllocatedCapacity() - intData.size;
+ QVERIFY(intDataFreeSpace > 0);
+ const size_t strDataFreeSpace = strData.constAllocatedCapacity() - strData.size;
+ QVERIFY(strDataFreeSpace > 0);
+ const size_t objDataFreeSpace = objData.constAllocatedCapacity() - objData.size;
+ QVERIFY(objDataFreeSpace > 0);
+ RUN_TEST_FUNC(testCopyAppend, intData, intDataFreeSpace, int(-1));
+ RUN_TEST_FUNC(testCopyAppend, strData, strDataFreeSpace, QLatin1String("foo"));
+ RUN_TEST_FUNC(testCopyAppend, objData, objDataFreeSpace, CountedObject());
+ QCOMPARE(intData.size, intData.constAllocatedCapacity());
+ QCOMPARE(strData.size, strData.constAllocatedCapacity());
+ QCOMPARE(objData.size, objData.constAllocatedCapacity());
+ }
+
+ // copyAppend (value version) - special case of copying self value
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testCopyAppendSelf = [&] (auto &dataPointer, size_t n, const auto &value) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ auto valueCopy = value;
+
+ dataPointer->copyAppend(n, value);
+ QCOMPARE(size_t(dataPointer.size), originalSize + n);
+ size_t i = 0;
+ for (; i < originalSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], valueCopy);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // make no free space at the end
+ intData->appendInitialize(intData.size + intData.freeSpaceAtEnd());
+ strData->appendInitialize(strData.size + strData.freeSpaceAtEnd());
+ objData->appendInitialize(objData.size + objData.freeSpaceAtEnd());
+
+ // make all values unique. this would ensure that we do not have erroneously passed test
+ int i = 0;
+ std::generate(intData.begin(), intData.end(), [&i] () { return i++; });
+ std::generate(strData.begin(), strData.end(), [&i] () { return QString::number(i++); });
+ std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); });
+
+ // sanity checks:
+ if (GrowthPosition & QArrayData::GrowsAtBeginning) {
+ QVERIFY(intData.freeSpaceAtBegin() > 0);
+ QVERIFY(strData.freeSpaceAtBegin() > 0);
+ QVERIFY(objData.freeSpaceAtBegin() > 0);
+ }
+ QVERIFY(intData.freeSpaceAtEnd() == 0);
+ QVERIFY(strData.freeSpaceAtEnd() == 0);
+ QVERIFY(objData.freeSpaceAtEnd() == 0);
+
+ // now, append to full size causing the data to move internally. passed
+ // value that refers to the object itself must be used correctly
+ RUN_TEST_FUNC(testCopyAppendSelf, intData, intData.freeSpaceAtBegin(), intData.data()[0]);
+ RUN_TEST_FUNC(testCopyAppendSelf, strData, strData.freeSpaceAtBegin(), strData.data()[0]);
+ RUN_TEST_FUNC(testCopyAppendSelf, objData, objData.freeSpaceAtBegin(), objData.data()[0]);
+ }
+
+ // moveAppend
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ // now there's only one version that accepts "T*" as input parameters
+ const auto testMoveAppend = [&] (auto &dataPointer, const auto &source)
+ {
+ const size_t originalSize = dataPointer.size;
+ const size_t addedSize = std::distance(source.begin(), source.end());
+ auto sourceCopy = source;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->moveAppend(sourceCopy.data(), sourceCopy.data() + sourceCopy.size());
+ QCOMPARE(size_t(dataPointer.size), originalSize + addedSize);
+ size_t i = 0;
+ for (; i < originalSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], source[i - originalSize]);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // empty range
+ RUN_TEST_FUNC(testMoveAppend, intData, std::array<int, 0>{});
+ RUN_TEST_FUNC(testMoveAppend, strData, std::array<QString, 0>{});
+ RUN_TEST_FUNC(testMoveAppend, objData, std::array<CountedObject, 0>{});
+
+ // non-empty range
+ RUN_TEST_FUNC(testMoveAppend, intData, intArray);
+ RUN_TEST_FUNC(testMoveAppend, strData, stringArray);
+ RUN_TEST_FUNC(testMoveAppend, objData, objArray);
+
+ // append to full
+ const size_t intDataFreeSpace = intData.constAllocatedCapacity() - intData.size;
+ QVERIFY(intDataFreeSpace > 0);
+ const size_t strDataFreeSpace = strData.constAllocatedCapacity() - strData.size;
+ QVERIFY(strDataFreeSpace > 0);
+ const size_t objDataFreeSpace = objData.constAllocatedCapacity() - objData.size;
+ QVERIFY(objDataFreeSpace > 0);
+ RUN_TEST_FUNC(testMoveAppend, intData, std::vector<int>(intDataFreeSpace, int(55)));
+ RUN_TEST_FUNC(testMoveAppend, strData,
+ std::vector<QString>(strDataFreeSpace, QLatin1String("barbaz")));
+ RUN_TEST_FUNC(testMoveAppend, objData,
+ std::vector<CountedObject>(objDataFreeSpace, CountedObject()));
+ QCOMPARE(intData.size, intData.constAllocatedCapacity());
+ QCOMPARE(strData.size, strData.constAllocatedCapacity());
+ QCOMPARE(objData.size, objData.constAllocatedCapacity());
+ }
+
+ // moveAppend - special case of moving from self (this is legal yet rather useless)
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testMoveAppendSelf = [&] (auto &dataPointer, auto first, auto last) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ const size_t addedSize = std::distance(first, last);
+ const size_t firstPos = std::distance(dataPointer->begin(), first);
+ auto firstCopy = copy->begin() + firstPos;
+
+ dataPointer->moveAppend(first, last);
+ QCOMPARE(size_t(dataPointer.size), originalSize + addedSize);
+ size_t i = 0;
+ for (; i < originalSize; ++i) {
+ if (i >= firstPos && i < (firstPos + addedSize)) // skip "moved from" chunk
+ continue;
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ }
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], *(firstCopy + (i - originalSize)));
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+ // make no free space at the end
+ intData->appendInitialize(intData.size + intData.freeSpaceAtEnd());
+ strData->appendInitialize(strData.size + strData.freeSpaceAtEnd());
+ objData->appendInitialize(objData.size + objData.freeSpaceAtEnd());
+
+ // make all values unique. this would ensure that we do not have erroneously passed test
+ int i = 0;
+ std::generate(intData.begin(), intData.end(), [&i] () { return i++; });
+ std::generate(strData.begin(), strData.end(), [&i] () { return QString::number(i++); });
+ std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); });
+
+ // sanity checks:
+ if (GrowthPosition & QArrayData::GrowsAtBeginning) {
+ QVERIFY(intData.freeSpaceAtBegin() > 0);
+ QVERIFY(strData.freeSpaceAtBegin() > 0);
+ QVERIFY(objData.freeSpaceAtBegin() > 0);
+ }
+ QVERIFY(intData.freeSpaceAtBegin() <= intData.size);
+ QVERIFY(strData.freeSpaceAtBegin() <= strData.size);
+ QVERIFY(objData.freeSpaceAtBegin() <= objData.size);
+ QVERIFY(intData.freeSpaceAtEnd() == 0);
+ QVERIFY(strData.freeSpaceAtEnd() == 0);
+ QVERIFY(objData.freeSpaceAtEnd() == 0);
+
+ // now, append to full size causing the data to move internally. passed
+ // iterators that refer to the object itself must be used correctly
+ RUN_TEST_FUNC(testMoveAppendSelf, intData, intData.begin(),
+ intData.begin() + intData.freeSpaceAtBegin());
+ RUN_TEST_FUNC(testMoveAppendSelf, strData, strData.begin(),
+ strData.begin() + strData.freeSpaceAtBegin());
+ RUN_TEST_FUNC(testMoveAppendSelf, objData, objData.begin(),
+ objData.begin() + objData.freeSpaceAtBegin());
+ }
+
+ // truncate
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testTruncate = [&] (auto &dataPointer, size_t newSize)
+ {
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ dataPointer->truncate(newSize);
+ QCOMPARE(size_t(dataPointer.size), newSize);
+ for (size_t i = 0; i < newSize; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(inputSize, inputSize);
+ // truncate one
+ RUN_TEST_FUNC(testTruncate, intData, inputSize - 1);
+ RUN_TEST_FUNC(testTruncate, strData, inputSize - 1);
+ RUN_TEST_FUNC(testTruncate, objData, inputSize - 1);
+
+ // truncate all
+ RUN_TEST_FUNC(testTruncate, intData, 0);
+ RUN_TEST_FUNC(testTruncate, strData, 0);
+ RUN_TEST_FUNC(testTruncate, objData, 0);
+ }
+
+ // insert
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testInsertRange = [&] (auto &dataPointer, size_t pos, auto first, auto last)
+ {
+ const size_t originalSize = dataPointer.size;
+ const size_t distance = std::distance(first, last);
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->insert(pos, first, last - first);
+ QCOMPARE(size_t(dataPointer.size), originalSize + distance);
+ size_t i = 0;
+ for (; i < pos; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < pos + distance; ++i)
+ QCOMPARE(dataPointer.data()[i], *(first + (i - pos)));
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i - distance]);
+ };
+
+ const auto testInsertValue = [&] (auto &dataPointer, size_t pos, size_t n, auto value)
+ {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->insert(pos, n, value);
+ QCOMPARE(size_t(dataPointer.size), originalSize + n);
+ size_t i = 0;
+ for (; i < pos; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < pos + n; ++i)
+ QCOMPARE(dataPointer.data()[i], value);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i - n]);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(100, 10);
+
+ // empty ranges
+ RUN_TEST_FUNC(testInsertRange, intData, 0, intArray.data(), intArray.data());
+ RUN_TEST_FUNC(testInsertRange, strData, 0, stringArray.data(), stringArray.data());
+ RUN_TEST_FUNC(testInsertRange, objData, 0, objArray.data(), objArray.data());
+ RUN_TEST_FUNC(testInsertValue, intData, 1, 0, int());
+ RUN_TEST_FUNC(testInsertValue, strData, 1, 0, QString());
+ RUN_TEST_FUNC(testInsertValue, objData, 1, 0, CountedObject());
+
+ // insert at the beginning
+ RUN_TEST_FUNC(testInsertRange, intData, 0, intArray.data(), intArray.data() + 1);
+ RUN_TEST_FUNC(testInsertRange, strData, 0, stringArray.data(), stringArray.data() + 1);
+ RUN_TEST_FUNC(testInsertRange, objData, 0, objArray.data(), objArray.data() + 1);
+ RUN_TEST_FUNC(testInsertValue, intData, 0, 1, int(-100));
+ RUN_TEST_FUNC(testInsertValue, strData, 0, 1, QLatin1String("12"));
+ RUN_TEST_FUNC(testInsertValue, objData, 0, 1, CountedObject());
+
+ // insert into the middle (with the left part of the data being smaller)
+ RUN_TEST_FUNC(testInsertRange, intData, 1, intArray.data() + 2, intArray.data() + 4);
+ RUN_TEST_FUNC(testInsertRange, strData, 1, stringArray.data() + 2, stringArray.data() + 4);
+ RUN_TEST_FUNC(testInsertRange, objData, 1, objArray.data() + 2, objArray.data() + 4);
+ RUN_TEST_FUNC(testInsertValue, intData, 2, 2, int(11));
+ RUN_TEST_FUNC(testInsertValue, strData, 2, 2, QLatin1String("abcdefxdeadbeef"));
+ RUN_TEST_FUNC(testInsertValue, objData, 2, 2, CountedObject());
+
+ // insert into the middle (with the right part of the data being smaller)
+ RUN_TEST_FUNC(testInsertRange, intData, intData.size - 1, intArray.data(),
+ intArray.data() + intArray.size());
+ RUN_TEST_FUNC(testInsertRange, strData, strData.size - 1, stringArray.data(),
+ stringArray.data() + stringArray.size());
+ RUN_TEST_FUNC(testInsertRange, objData, objData.size - 1, objArray.data(),
+ objArray.data() + objArray.size());
+ RUN_TEST_FUNC(testInsertValue, intData, intData.size - 3, 3, int(512));
+ RUN_TEST_FUNC(testInsertValue, strData, strData.size - 3, 3, QLatin1String("foo"));
+ RUN_TEST_FUNC(testInsertValue, objData, objData.size - 3, 3, CountedObject());
+
+ // insert at the end
+ RUN_TEST_FUNC(testInsertRange, intData, intData.size, intArray.data(), intArray.data() + 3);
+ RUN_TEST_FUNC(testInsertRange, strData, strData.size, stringArray.data(),
+ stringArray.data() + 3);
+ RUN_TEST_FUNC(testInsertRange, objData, objData.size, objArray.data(), objArray.data() + 3);
+ RUN_TEST_FUNC(testInsertValue, intData, intData.size, 1, int(-42));
+ RUN_TEST_FUNC(testInsertValue, strData, strData.size, 1, QLatin1String("hello, world"));
+ RUN_TEST_FUNC(testInsertValue, objData, objData.size, 1, CountedObject());
+ }
+
+ // insert - special case of inserting from self value. this test only makes
+ // sense for prepend - insert at begin.
+ {
+ const auto testInsertValueSelf = [&] (auto &dataPointer, size_t n, const auto &value) {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+ auto valueCopy = value;
+
+ dataPointer->insert(0, n, value);
+ QCOMPARE(size_t(dataPointer.size), originalSize + n);
+ size_t i = 0;
+ for (; i < n; ++i)
+ QCOMPARE(dataPointer.data()[i], valueCopy);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i - n]);
+ };
+
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ auto [intData, strData, objData] = setupDataPointers(inputSize * 2, inputSize / 2);
+
+ // make no free space at the begin
+ intData->insert(0, intData.freeSpaceAtBegin(), intData.data()[0]);
+ strData->insert(0, strData.freeSpaceAtBegin(), strData.data()[0]);
+ objData->insert(0, objData.freeSpaceAtBegin(), objData.data()[0]);
+
+ // make all values unique. this would ensure that we do not have erroneously passed test
+ int i = 0;
+ std::generate(intData.begin(), intData.end(), [&i] () { return i++; });
+ std::generate(strData.begin(), strData.end(), [&i] () { return QString::number(i++); });
+ std::generate(objData.begin(), objData.end(), [] () { return CountedObject(); });
+
+ // sanity checks:
+ QVERIFY(intData.freeSpaceAtEnd() > 0);
+ QVERIFY(strData.freeSpaceAtEnd() > 0);
+ QVERIFY(objData.freeSpaceAtEnd() > 0);
+ QVERIFY(intData.freeSpaceAtBegin() == 0);
+ QVERIFY(strData.freeSpaceAtBegin() == 0);
+ QVERIFY(objData.freeSpaceAtBegin() == 0);
+
+ // now, prepend to full size causing the data to move internally. passed
+ // value that refers to the object itself must be used correctly
+ RUN_TEST_FUNC(testInsertValueSelf, intData, intData.freeSpaceAtEnd(),
+ intData.data()[intData.size - 1]);
+ RUN_TEST_FUNC(testInsertValueSelf, strData, strData.freeSpaceAtEnd(),
+ strData.data()[strData.size - 1]);
+ RUN_TEST_FUNC(testInsertValueSelf, objData, objData.freeSpaceAtEnd(),
+ objData.data()[objData.size - 1]);
+ }
+
+ // emplace
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ // testing simple case when emplacing a copy of the same type
+ const auto testEmplace = [&] (auto &dataPointer, size_t pos, auto value)
+ {
+ const size_t originalSize = dataPointer.size;
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->emplace(pos, value);
+ QCOMPARE(size_t(dataPointer.size), originalSize + 1);
+ size_t i = 0;
+ for (; i < pos; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ QCOMPARE(dataPointer.data()[i++], value);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i - 1]);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(20, 5);
+
+ // emplace at the beginning
+ RUN_TEST_FUNC(testEmplace, intData, 0, int(2));
+ RUN_TEST_FUNC(testEmplace, strData, 0, QLatin1String("foo"));
+ RUN_TEST_FUNC(testEmplace, objData, 0, CountedObject());
+ // emplace into the middle (with the left part of the data being smaller)
+ RUN_TEST_FUNC(testEmplace, intData, 1, int(-1));
+ RUN_TEST_FUNC(testEmplace, strData, 1, QLatin1String("bar"));
+ RUN_TEST_FUNC(testEmplace, objData, 1, CountedObject());
+ // emplace into the middle (with the right part of the data being smaller)
+ RUN_TEST_FUNC(testEmplace, intData, intData.size - 2, int(42));
+ RUN_TEST_FUNC(testEmplace, strData, strData.size - 2, QLatin1String("baz"));
+ RUN_TEST_FUNC(testEmplace, objData, objData.size - 2, CountedObject());
+ // emplace at the end
+ RUN_TEST_FUNC(testEmplace, intData, intData.size, int(123));
+ RUN_TEST_FUNC(testEmplace, strData, strData.size, QLatin1String("bak"));
+ RUN_TEST_FUNC(testEmplace, objData, objData.size, CountedObject());
+ }
+
+ // erase
+ {
+ CountedObject::LeakChecker localLeakChecker; Q_UNUSED(localLeakChecker);
+ const auto testErase = [&] (auto &dataPointer, auto first, auto last)
+ {
+ const size_t originalSize = dataPointer.size;
+ const size_t distance = std::distance(first, last);
+ const size_t pos = std::distance(dataPointer.begin(), first);
+ auto copy = cloneArrayDataPointer(dataPointer, dataPointer.size);
+
+ dataPointer->erase(first, last - first);
+ QCOMPARE(size_t(dataPointer.size), originalSize - distance);
+ size_t i = 0;
+ for (; i < pos; ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i]);
+ for (; i < size_t(dataPointer.size); ++i)
+ QCOMPARE(dataPointer.data()[i], copy.data()[i + distance]);
+ };
+
+ auto [intData, strData, objData] = setupDataPointers(100, 100);
+
+ // erase chunk from the beginning
+ RUN_TEST_FUNC(testErase, intData, intData.begin(), intData.begin() + 10);
+ RUN_TEST_FUNC(testErase, strData, strData.begin(), strData.begin() + 10);
+ RUN_TEST_FUNC(testErase, objData, objData.begin(), objData.begin() + 10);
+
+ // erase chunk from the end
+ RUN_TEST_FUNC(testErase, intData, intData.end() - 10, intData.end());
+ RUN_TEST_FUNC(testErase, strData, strData.end() - 10, strData.end());
+ RUN_TEST_FUNC(testErase, objData, objData.end() - 10, objData.end());
+
+ // erase the middle chunk
+ RUN_TEST_FUNC(testErase, intData, intData.begin() + (intData.size / 2) - 5,
+ intData.begin() + (intData.size / 2) + 5);
+ RUN_TEST_FUNC(testErase, strData, strData.begin() + (strData.size / 2) - 5,
+ strData.begin() + (strData.size / 2) + 5);
+ RUN_TEST_FUNC(testErase, objData, objData.begin() + (objData.size / 2) - 5,
+ objData.begin() + (objData.size / 2) + 5);
+
+ // erase chunk in the left part of the data
+ RUN_TEST_FUNC(testErase, intData, intData.begin() + 1, intData.begin() + 6);
+ RUN_TEST_FUNC(testErase, strData, strData.begin() + 1, strData.begin() + 6);
+ RUN_TEST_FUNC(testErase, objData, objData.begin() + 1, objData.begin() + 6);
+
+ // erase chunk in the right part of the data
+ RUN_TEST_FUNC(testErase, intData, intData.end() - 6, intData.end() - 1);
+ RUN_TEST_FUNC(testErase, strData, strData.end() - 6, strData.end() - 1);
+ RUN_TEST_FUNC(testErase, objData, objData.end() - 6, objData.end() - 1);
+
+ // erase all
+ RUN_TEST_FUNC(testErase, intData, intData.begin(), intData.end());
+ RUN_TEST_FUNC(testErase, strData, strData.begin(), strData.end());
+ RUN_TEST_FUNC(testErase, objData, objData.begin(), objData.end());
+ }
}
+Q_DECLARE_METATYPE(QArrayDataPointer<int>)
+
struct ResetOnDtor
{
ResetOnDtor()
@@ -1180,15 +1727,15 @@ void fromRawData_impl()
{
// Default: Immutable, sharable
SimpleVector<T> raw = SimpleVector<T>::fromRawData(array,
- sizeof(array)/sizeof(array[0]), QArrayData::DefaultRawFlags);
+ sizeof(array)/sizeof(array[0]));
QCOMPARE(raw.size(), size_t(11));
QCOMPARE((const T *)raw.constBegin(), array);
QCOMPARE((const T *)raw.constEnd(), (const T *)(array + sizeof(array)/sizeof(array[0])));
- QVERIFY(!raw.isShared());
+ QVERIFY(raw.isShared());
QVERIFY(SimpleVector<T>(raw).isSharedWith(raw));
- QVERIFY(!raw.isShared());
+ QVERIFY(raw.isShared());
// Detach
QCOMPARE(raw.back(), T(11));
@@ -1225,46 +1772,62 @@ void tst_QArrayData::literals()
{
{
QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char, "ABCDEFGHIJ");
- QCOMPARE(d.size, 10u + 1u);
+ QCOMPARE(d.size, 10 + 1);
for (int i = 0; i < 10; ++i)
QCOMPARE(d.data()[i], char('A' + i));
}
{
- // wchar_t is not necessarily 2-bytes
- QArrayDataPointer<wchar_t> d = Q_ARRAY_LITERAL(wchar_t, L"ABCDEFGHIJ");
- QCOMPARE(d.size, 10u + 1u);
+ QList<char> l(Q_ARRAY_LITERAL(char, "ABCDEFGHIJ"));
+ QCOMPARE(l.size(), 11);
+ QCOMPARE(l.capacity(), 0);
for (int i = 0; i < 10; ++i)
- QCOMPARE(d.data()[i], wchar_t('A' + i));
- }
-
- {
- SimpleVector<char> v = Q_ARRAY_LITERAL(char, "ABCDEFGHIJ");
+ QCOMPARE(l.at(i), char('A' + i));
- QVERIFY(!v.isNull());
- QVERIFY(!v.isEmpty());
- QCOMPARE(v.size(), size_t(11));
- // v.capacity() is unspecified, for now
-
- QVERIFY(v.isStatic());
- QCOMPARE((void*)(const char*)(v.constBegin() + v.size()), (void*)(const char*)v.constEnd());
+ (void)l.begin(); // "detach"
+ QCOMPARE(l.size(), 11);
+ QVERIFY(l.capacity() >= l.size());
for (int i = 0; i < 10; ++i)
- QCOMPARE(const_(v)[i], char('A' + i));
- QCOMPARE(const_(v)[10], char('\0'));
+ QCOMPARE(l[i], char('A' + i));
}
{
- struct LiteralType {
- int value;
- Q_DECL_CONSTEXPR LiteralType(int v = 0) : value(v) {}
- };
+ // wchar_t is not necessarily 2-bytes
+ QArrayDataPointer<wchar_t> d = Q_ARRAY_LITERAL(wchar_t, L"ABCDEFGHIJ");
+ QCOMPARE(d.size, 10 + 1);
+ for (int i = 0; i < 10; ++i)
+ QCOMPARE(d.data()[i], wchar_t('A' + i));
+ }
+ struct LiteralType {
+ int value;
+ constexpr LiteralType(int v = 0) : value(v) {}
+ };
+
+ {
QArrayDataPointer<LiteralType> d = Q_ARRAY_LITERAL(LiteralType, LiteralType(0), LiteralType(1), LiteralType(2));
QCOMPARE(d->size, 3);
for (int i = 0; i < 3; ++i)
QCOMPARE(d->data()[i].value, i);
}
+
+ {
+ QList<LiteralType> l(Q_ARRAY_LITERAL(LiteralType, LiteralType(0), LiteralType(1), LiteralType(2)));
+ QCOMPARE(l.size(), 3);
+ QCOMPARE(l.capacity(), 0);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(l.at(i).value, i);
+ l.squeeze(); // shouldn't detach
+ QCOMPARE(l.capacity(), 0);
+
+ (void)l.begin(); // "detach"
+
+ QCOMPARE(l.size(), 3);
+ QVERIFY(l.capacity() >= l.size());
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(l[i].value, i);
+ }
}
// Variadic Q_ARRAY_LITERAL need to be available in the current configuration.
@@ -1273,7 +1836,7 @@ void tst_QArrayData::variadicLiterals()
{
QArrayDataPointer<int> d =
Q_ARRAY_LITERAL(int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
- QCOMPARE(d.size, 10u);
+ QCOMPARE(d.size, 10);
for (int i = 0; i < 10; ++i)
QCOMPARE(d.data()[i], i);
}
@@ -1281,7 +1844,7 @@ void tst_QArrayData::variadicLiterals()
{
QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char,
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
- QCOMPARE(d.size, 10u);
+ QCOMPARE(d.size, 10);
for (int i = 0; i < 10; ++i)
QCOMPARE(d.data()[i], char('A' + i));
}
@@ -1289,27 +1852,12 @@ void tst_QArrayData::variadicLiterals()
{
QArrayDataPointer<const char *> d = Q_ARRAY_LITERAL(const char *,
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J");
- QCOMPARE(d.size, 10u);
+ QCOMPARE(d.size, 10);
for (int i = 0; i < 10; ++i) {
QCOMPARE(d.data()[i][0], char('A' + i));
QCOMPARE(d.data()[i][1], '\0');
}
}
-
- {
- SimpleVector<int> v = Q_ARRAY_LITERAL(int, 0, 1, 2, 3, 4, 5, 6);
-
- QVERIFY(!v.isNull());
- QVERIFY(!v.isEmpty());
- QCOMPARE(v.size(), size_t(7));
- // v.capacity() is unspecified, for now
-
- QVERIFY(v.isStatic());
- QCOMPARE((const int *)(v.constBegin() + v.size()), (const int *)v.constEnd());
-
- for (int i = 0; i < 7; ++i)
- QCOMPARE(const_(v)[i], i);
- }
}
// std::remove_reference is in C++11, but requires library support
@@ -1333,17 +1881,17 @@ struct CompilerHasCxx11ImplicitMoves
struct DetectConstructor
{
- Q_DECL_CONSTEXPR DetectConstructor()
+ constexpr DetectConstructor()
: constructor(DefaultConstructor)
{
}
- Q_DECL_CONSTEXPR DetectConstructor(const DetectConstructor &)
+ constexpr DetectConstructor(const DetectConstructor &)
: constructor(CopyConstructor)
{
}
- Q_DECL_CONSTEXPR DetectConstructor(DetectConstructor &&)
+ constexpr DetectConstructor(DetectConstructor &&)
: constructor(MoveConstructor)
{
}
@@ -1443,5 +1991,546 @@ void tst_QArrayData::grow()
}
}
+void tst_QArrayData::freeSpace_data()
+{
+ QTest::addColumn<size_t>("n");
+
+ for (const size_t n : {1, 3, 5, 7, 16, 25}) {
+ QString suffix = QString::number(n) + QLatin1String("-elements");
+ QTest::newRow(qPrintable(QLatin1String("alloc-") + suffix))
+ << n;
+ }
+}
+
+void tst_QArrayData::freeSpace()
+{
+ QFETCH(size_t, n);
+ const auto testFreeSpace = [] (auto dummy, qsizetype n) {
+ using Type = std::decay_t<decltype(dummy)>;
+ using DataPointer = QArrayDataPointer<Type>;
+ Q_UNUSED(dummy);
+ const qsizetype capacity = n + 1;
+ auto ptr = DataPointer::allocateGrow(DataPointer(), capacity, QArrayData::GrowsAtEnd);
+ const auto alloc = qsizetype(ptr.constAllocatedCapacity());
+ QVERIFY(alloc >= capacity);
+ QCOMPARE(ptr.freeSpaceAtBegin() + ptr.freeSpaceAtEnd(), alloc);
+ };
+ RUN_TEST_FUNC(testFreeSpace, char(0), n);
+ RUN_TEST_FUNC(testFreeSpace, char16_t(0), n);
+ RUN_TEST_FUNC(testFreeSpace, int(0), n);
+ RUN_TEST_FUNC(testFreeSpace, QString(), n);
+ RUN_TEST_FUNC(testFreeSpace, CountedObject(), n);
+}
+
+void tst_QArrayData::dataPointerAllocate_data()
+{
+ QTest::addColumn<QArrayData::GrowthPosition>("GrowthPosition");
+
+ QTest::newRow("at-end") << QArrayData::GrowsAtEnd;
+ QTest::newRow("at-begin") << QArrayData::GrowsAtBeginning;
+}
+
+void tst_QArrayData::dataPointerAllocate()
+{
+ QFETCH(QArrayData::GrowthPosition, GrowthPosition);
+ const auto createDataPointer = [] (qsizetype capacity, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ Q_UNUSED(initValue);
+ return QArrayDataPointer<Type>(capacity);
+ };
+
+ const auto testRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ using DataPointer = QArrayDataPointer<Type>;
+
+ auto oldDataPointer = createDataPointer(capacity, initValue);
+ oldDataPointer->insert(0, 1, initValue);
+ oldDataPointer->insert(0, 1, initValue); // trigger prepend
+ QVERIFY(!oldDataPointer.needsDetach());
+
+ auto newDataPointer = DataPointer::allocateGrow(oldDataPointer, newSize, GrowthPosition);
+ const auto newAlloc = newDataPointer.constAllocatedCapacity();
+ const auto freeAtBegin = newDataPointer.freeSpaceAtBegin();
+ const auto freeAtEnd = newDataPointer.freeSpaceAtEnd();
+
+ QVERIFY(newAlloc >= oldDataPointer.constAllocatedCapacity());
+ QCOMPARE(freeAtBegin + freeAtEnd, newAlloc);
+ if (GrowthPosition == QArrayData::GrowsAtBeginning) {
+ QVERIFY(freeAtBegin > 0);
+ } else if (GrowthPosition & QArrayData::GrowsAtEnd) {
+ QCOMPARE(freeAtBegin, oldDataPointer.freeSpaceAtBegin());
+ QVERIFY(freeAtEnd > 0);
+ }
+ };
+
+ for (size_t n : {10, 512, 1000}) {
+ RUN_TEST_FUNC(testRealloc, n, n + 1, int(0));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, char('a'));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, char16_t(u'a'));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, QString("hello, world!"));
+ RUN_TEST_FUNC(testRealloc, n, n + 1, CountedObject());
+ }
+
+ const auto testDetachRealloc = [&] (qsizetype capacity, qsizetype newSize, auto initValue) {
+ using Type = std::decay_t<decltype(initValue)>;
+ using DataPointer = QArrayDataPointer<Type>;
+
+ auto oldDataPointer = createDataPointer(capacity, initValue);
+ oldDataPointer->insert(0, 1, initValue); // trigger prepend
+ auto oldDataPointerCopy = oldDataPointer; // force detach later
+ QVERIFY(oldDataPointer.needsDetach());
+
+ auto newDataPointer = DataPointer::allocateGrow(oldDataPointer, oldDataPointer->detachCapacity(newSize), GrowthPosition);
+ const auto newAlloc = newDataPointer.constAllocatedCapacity();
+ const auto freeAtBegin = newDataPointer.freeSpaceAtBegin();
+ const auto freeAtEnd = newDataPointer.freeSpaceAtEnd();
+
+ QVERIFY(newAlloc > oldDataPointer.constAllocatedCapacity());
+ QCOMPARE(freeAtBegin + freeAtEnd, newAlloc);
+ if (GrowthPosition == QArrayData::GrowsAtBeginning) {
+ QVERIFY(freeAtBegin > 0);
+ } else if (GrowthPosition & QArrayData::GrowsAtEnd) {
+ QCOMPARE(freeAtBegin, oldDataPointer.freeSpaceAtBegin());
+ QVERIFY(freeAtEnd > 0);
+ }
+ };
+
+ for (size_t n : {10, 512, 1000}) {
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, int(0));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, char('a'));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, char16_t(u'a'));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, QString("hello, world!"));
+ RUN_TEST_FUNC(testDetachRealloc, n, n + 1, CountedObject());
+ }
+}
+
+struct MyQStringWrapper : public QString
+{
+ bool movedTo = false;
+ bool movedFrom = false;
+ MyQStringWrapper() = default;
+ MyQStringWrapper(QChar c) : QString(c) { }
+ MyQStringWrapper(MyQStringWrapper &&other) : QString(std::move(static_cast<QString &>(other)))
+ {
+ movedTo = true;
+ movedFrom = other.movedFrom;
+ other.movedFrom = true;
+ }
+ MyQStringWrapper &operator=(MyQStringWrapper &&other)
+ {
+ QString::operator=(std::move(static_cast<QString &>(other)));
+ movedTo = true;
+ movedFrom = other.movedFrom;
+ other.movedFrom = true;
+ return *this;
+ }
+ MyQStringWrapper(const MyQStringWrapper &) = default;
+ MyQStringWrapper &operator=(const MyQStringWrapper &) = default;
+ ~MyQStringWrapper() = default;
+};
+
+struct MyMovableQString : public MyQStringWrapper
+{
+ MyMovableQString() = default;
+ MyMovableQString(QChar c) : MyQStringWrapper(c) { }
+
+private:
+ friend bool operator==(const MyMovableQString &a, QChar c)
+ {
+ return static_cast<QString>(a) == QString(c);
+ }
+
+ friend bool operator==(const MyMovableQString &a, const MyMovableQString &b)
+ {
+ return static_cast<QString>(a) == static_cast<QString>(b);
+ }
+};
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(MyMovableQString, Q_RELOCATABLE_TYPE);
+QT_END_NAMESPACE
+static_assert(QTypeInfo<MyMovableQString>::isComplex);
+static_assert(QTypeInfo<MyMovableQString>::isRelocatable);
+
+struct MyComplexQString : public MyQStringWrapper
+{
+ MyComplexQString() = default;
+ MyComplexQString(QChar c) : MyQStringWrapper(c) { }
+
+private:
+ friend bool operator==(const MyComplexQString &a, QChar c)
+ {
+ return static_cast<QString>(a) == QString(c);
+ }
+
+ friend bool operator==(const MyComplexQString &a, const MyComplexQString &b)
+ {
+ return static_cast<QString>(a) == static_cast<QString>(b);
+ }
+};
+static_assert(QTypeInfo<MyComplexQString>::isComplex);
+static_assert(!QTypeInfo<MyComplexQString>::isRelocatable);
+
+void tst_QArrayData::selfEmplaceBackwards()
+{
+ const auto createDataPointer = [](qsizetype capacity, int spaceAtEnd, auto dummy) {
+ using Type = std::decay_t<decltype(dummy)>;
+ Q_UNUSED(dummy);
+ auto [header, ptr] = QTypedArrayData<Type>::allocate(capacity, QArrayData::Grow);
+ // do custom adjustments to make sure there's free space at end
+ ptr += header->alloc - spaceAtEnd;
+ return QArrayDataPointer(header, ptr);
+ };
+
+ const auto testSelfEmplace = [&](auto dummy, int spaceAtEnd, auto initValues) {
+ auto adp = createDataPointer(100, spaceAtEnd, dummy);
+ for (auto v : initValues) {
+ adp->emplace(adp.size, v);
+ }
+ QVERIFY(!adp.freeSpaceAtEnd());
+ QVERIFY(adp.freeSpaceAtBegin());
+
+ adp->emplace(adp.size, adp.data()[0]);
+ for (qsizetype i = 0; i < adp.size - 1; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i]);
+ }
+ QCOMPARE(adp.data()[adp.size - 1], initValues[0]);
+
+ adp->emplace(adp.size, std::move(adp.data()[0]));
+ for (qsizetype i = 1; i < adp.size - 2; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i]);
+ }
+ QCOMPARE(adp.data()[adp.size - 2], initValues[0]);
+ QCOMPARE(adp.data()[0].movedFrom, true);
+ QCOMPARE(adp.data()[adp.size - 1], initValues[0]);
+ QCOMPARE(adp.data()[adp.size - 1].movedTo, true);
+ };
+
+ QList<QChar> movableObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyMovableQString(), 4, movableObjs);
+ QList<QChar> complexObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyComplexQString(), 4, complexObjs);
+}
+
+void tst_QArrayData::selfEmplaceForward()
+{
+ const auto createDataPointer = [](qsizetype capacity, int spaceAtBegin, auto dummy) {
+ using Type = std::decay_t<decltype(dummy)>;
+ Q_UNUSED(dummy);
+ auto [header, ptr] = QTypedArrayData<Type>::allocate(capacity, QArrayData::Grow);
+ // do custom adjustments to make sure there's free space at end
+ ptr += spaceAtBegin;
+ return QArrayDataPointer(header, ptr);
+ };
+
+ const auto testSelfEmplace = [&](auto dummy, int spaceAtBegin, auto initValues) {
+ // need a -1 below as the first emplace will go towards the end (as the array is still empty)
+ auto adp = createDataPointer(100, spaceAtBegin - 1, dummy);
+ auto reversedInitValues = initValues;
+ std::reverse(reversedInitValues.begin(), reversedInitValues.end());
+ for (auto v : reversedInitValues) {
+ adp->emplace(0, v);
+ }
+ QVERIFY(!adp.freeSpaceAtBegin());
+ QVERIFY(adp.freeSpaceAtEnd());
+
+ adp->emplace(0, adp.data()[adp.size - 1]);
+ for (qsizetype i = 1; i < adp.size; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i - 1]);
+ }
+ QCOMPARE(adp.data()[0], initValues[spaceAtBegin - 1]);
+
+ adp->emplace(0, std::move(adp.data()[adp.size - 1]));
+ for (qsizetype i = 2; i < adp.size - 1; ++i) {
+ QCOMPARE(adp.data()[i], initValues[i - 2]);
+ }
+ QCOMPARE(adp.data()[1], initValues[spaceAtBegin - 1]);
+ QCOMPARE(adp.data()[adp.size - 1].movedFrom, true);
+ QCOMPARE(adp.data()[0], initValues[spaceAtBegin - 1]);
+ QCOMPARE(adp.data()[0].movedTo, true);
+ };
+
+ QList<QChar> movableObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyMovableQString(), 4, movableObjs);
+ QList<QChar> complexObjs { u'a', u'b', u'c', u'd' };
+ RUN_TEST_FUNC(testSelfEmplace, MyComplexQString(), 4, complexObjs);
+}
+
+#ifndef QT_NO_EXCEPTIONS
+struct ThrowingTypeWatcher
+{
+ std::vector<void *> destroyedAddrs;
+ bool watch = false;
+
+ void destroyed(void *addr)
+ {
+ if (watch)
+ destroyedAddrs.push_back(addr);
+ }
+};
+
+ThrowingTypeWatcher &throwingTypeWatcher()
+{
+ static ThrowingTypeWatcher global;
+ return global;
+}
+
+struct ThrowingType
+{
+ static unsigned int throwOnce;
+ static constexpr char throwString[] = "Requested to throw";
+ enum MoveCase {
+ MoveRightNoOverlap,
+ MoveRightOverlap,
+ MoveLeftNoOverlap,
+ MoveLeftOverlap,
+ };
+ enum ThrowCase {
+ NoThrow,
+ ThrowInUninitializedRegion,
+ ThrowInOverlapRegion,
+ };
+
+ // reinforce basic checkers with std::shared_ptr which happens to signal
+ // very explicitly about use-after-free and so on under ASan
+ std::shared_ptr<int> doubleFreeHelper = std::shared_ptr<int>(new int(42));
+ int id = 0;
+
+ void checkThrow()
+ {
+ // deferred throw
+ if (throwOnce > 0) {
+ --throwOnce;
+ if (throwOnce == 0) {
+ throw std::runtime_error(throwString);
+ }
+ }
+ return;
+ }
+
+ void copy(const ThrowingType &other) noexcept(false)
+ {
+ doubleFreeHelper = other.doubleFreeHelper;
+ id = other.id;
+ checkThrow();
+ }
+
+ ThrowingType(int val = 0) noexcept(false) : id(val) { checkThrow(); }
+ ThrowingType(const ThrowingType &other) noexcept(false) { copy(other); }
+ ThrowingType &operator=(const ThrowingType &other) noexcept(false)
+ {
+ copy(other);
+ return *this;
+ }
+ ThrowingType(ThrowingType &&other) noexcept(false) { copy(other); }
+ ThrowingType &operator=(ThrowingType &&other) noexcept(false)
+ {
+ copy(other);
+ return *this;
+ }
+ ~ThrowingType() noexcept(true)
+ {
+ throwingTypeWatcher().destroyed(this); // notify global watcher
+ id = -1;
+ // if we're in dtor but use_count is 0, it's double free
+ QVERIFY(doubleFreeHelper.use_count() > 0);
+ }
+
+ friend bool operator==(const ThrowingType &a, const ThrowingType &b) { return a.id == b.id; }
+};
+
+unsigned int ThrowingType::throwOnce = 0;
+static_assert(!QTypeInfo<ThrowingType>::isRelocatable);
+
+void tst_QArrayData::relocateWithExceptions_data()
+{
+ QTest::addColumn<ThrowingType::MoveCase>("moveCase");
+ QTest::addColumn<ThrowingType::ThrowCase>("throwCase");
+ // Not throwing
+ QTest::newRow("no-throw-move-right-no-overlap")
+ << ThrowingType::MoveRightNoOverlap << ThrowingType::NoThrow;
+ QTest::newRow("no-throw-move-right-overlap")
+ << ThrowingType::MoveRightOverlap << ThrowingType::NoThrow;
+ QTest::newRow("no-throw-move-left-no-overlap")
+ << ThrowingType::MoveLeftNoOverlap << ThrowingType::NoThrow;
+ QTest::newRow("no-throw-move-left-overlap")
+ << ThrowingType::MoveLeftOverlap << ThrowingType::NoThrow;
+ // Throwing in uninitialized region
+ QTest::newRow("throw-in-uninit-region-move-right-no-overlap")
+ << ThrowingType::MoveRightNoOverlap << ThrowingType::ThrowInUninitializedRegion;
+ QTest::newRow("throw-in-uninit-region-move-right-overlap")
+ << ThrowingType::MoveRightOverlap << ThrowingType::ThrowInUninitializedRegion;
+ QTest::newRow("throw-in-uninit-region-move-left-no-overlap")
+ << ThrowingType::MoveLeftNoOverlap << ThrowingType::ThrowInUninitializedRegion;
+ QTest::newRow("throw-in-uninit-region-move-left-overlap")
+ << ThrowingType::MoveLeftOverlap << ThrowingType::ThrowInUninitializedRegion;
+ // Throwing in overlap region
+ QTest::newRow("throw-in-overlap-region-move-right-overlap")
+ << ThrowingType::MoveRightOverlap << ThrowingType::ThrowInOverlapRegion;
+ QTest::newRow("throw-in-overlap-region-move-left-overlap")
+ << ThrowingType::MoveLeftOverlap << ThrowingType::ThrowInOverlapRegion;
+}
+
+void tst_QArrayData::relocateWithExceptions()
+{
+ // Assume that non-throwing moves perform correctly. Otherwise, all previous
+ // tests would've failed. Test only what happens when exceptions are thrown.
+ QFETCH(ThrowingType::MoveCase, moveCase);
+ QFETCH(ThrowingType::ThrowCase, throwCase);
+
+ struct ThrowingTypeLeakChecker
+ {
+ ThrowingType::MoveCase moveCase;
+ ThrowingType::ThrowCase throwCase;
+ size_t containerSize = 0;
+
+ ThrowingTypeLeakChecker(ThrowingType::MoveCase mc, ThrowingType::ThrowCase tc)
+ : moveCase(mc), throwCase(tc)
+ {
+ }
+
+ void start(qsizetype size)
+ {
+ containerSize = size_t(size);
+ throwingTypeWatcher().watch = true;
+ }
+
+ ~ThrowingTypeLeakChecker()
+ {
+ const size_t destroyedElementsCount = throwingTypeWatcher().destroyedAddrs.size();
+ const size_t destroyedElementsUniqueCount =
+ std::set<void *>(throwingTypeWatcher().destroyedAddrs.begin(),
+ throwingTypeWatcher().destroyedAddrs.end())
+ .size();
+
+ // reset the global watcher first and only then verify things
+ throwingTypeWatcher().watch = false;
+ throwingTypeWatcher().destroyedAddrs.clear();
+
+ size_t deletedByRelocate = 0;
+ switch (throwCase) {
+ case ThrowingType::NoThrow:
+ // if no overlap, N elements from old range. otherwise, N - 1
+ // elements from old range
+ if (moveCase == ThrowingType::MoveLeftNoOverlap
+ || moveCase == ThrowingType::MoveRightNoOverlap) {
+ deletedByRelocate = containerSize;
+ } else {
+ deletedByRelocate = containerSize - 1;
+ }
+ break;
+ case ThrowingType::ThrowInUninitializedRegion:
+ // 1 relocated element from uninitialized region
+ deletedByRelocate = 1u;
+ break;
+ case ThrowingType::ThrowInOverlapRegion:
+ // 2 relocated elements from uninitialized region
+ deletedByRelocate = 2u;
+ break;
+ default:
+ QFAIL("Unknown throwCase");
+ }
+
+ QCOMPARE(destroyedElementsCount, deletedByRelocate + containerSize);
+ QCOMPARE(destroyedElementsUniqueCount, destroyedElementsCount);
+ }
+ };
+
+ const auto setDeferredThrow = [throwCase]() {
+ switch (throwCase) {
+ case ThrowingType::NoThrow:
+ break; // do nothing
+ case ThrowingType::ThrowInUninitializedRegion:
+ ThrowingType::throwOnce = 2;
+ break;
+ case ThrowingType::ThrowInOverlapRegion:
+ ThrowingType::throwOnce = 3;
+ break;
+ default:
+ QFAIL("Unknown throwCase");
+ }
+ };
+
+ const auto createDataPointer = [](qsizetype capacity, qsizetype initSize) {
+ QArrayDataPointer<ThrowingType> qadp(capacity);
+ qadp->appendInitialize(initSize);
+ int i = 0;
+ std::generate(qadp.begin(), qadp.end(), [&i]() { return ThrowingType(i++); });
+ return qadp;
+ };
+
+ switch (moveCase) {
+ case ThrowingType::MoveRightNoOverlap: {
+ ThrowingTypeLeakChecker watch(moveCase, throwCase);
+ auto storage = createDataPointer(20, 3);
+ QVERIFY(storage.freeSpaceAtEnd() > 3);
+
+ watch.start(storage.size);
+ try {
+ setDeferredThrow();
+ storage->relocate(4);
+ if (throwCase != ThrowingType::NoThrow)
+ QFAIL("Unreachable line!");
+ } catch (const std::runtime_error &e) {
+ QCOMPARE(std::string(e.what()), ThrowingType::throwString);
+ }
+ break;
+ }
+ case ThrowingType::MoveRightOverlap: {
+ ThrowingTypeLeakChecker watch(moveCase, throwCase);
+ auto storage = createDataPointer(20, 3);
+ QVERIFY(storage.freeSpaceAtEnd() > 3);
+
+ watch.start(storage.size);
+ try {
+ setDeferredThrow();
+ storage->relocate(2);
+ if (throwCase != ThrowingType::NoThrow)
+ QFAIL("Unreachable line!");
+ } catch (const std::runtime_error &e) {
+ QCOMPARE(std::string(e.what()), ThrowingType::throwString);
+ }
+ break;
+ }
+ case ThrowingType::MoveLeftNoOverlap: {
+ ThrowingTypeLeakChecker watch(moveCase, throwCase);
+ auto storage = createDataPointer(20, 2);
+ storage->insert(0, 1, ThrowingType(42));
+ QVERIFY(storage.freeSpaceAtBegin() > 3);
+
+ watch.start(storage.size);
+ try {
+ setDeferredThrow();
+ storage->relocate(-4);
+ if (throwCase != ThrowingType::NoThrow)
+ QFAIL("Unreachable line!");
+ } catch (const std::runtime_error &e) {
+ QCOMPARE(std::string(e.what()), ThrowingType::throwString);
+ }
+ break;
+ }
+ case ThrowingType::MoveLeftOverlap: {
+ ThrowingTypeLeakChecker watch(moveCase, throwCase);
+ auto storage = createDataPointer(20, 2);
+ storage->insert(0, 1, ThrowingType(42));
+ QVERIFY(storage.freeSpaceAtBegin() > 3);
+
+ watch.start(storage.size);
+ try {
+ setDeferredThrow();
+ storage->relocate(-2);
+ if (throwCase != ThrowingType::NoThrow)
+ QFAIL("Unreachable line!");
+ } catch (const std::runtime_error &e) {
+ QCOMPARE(std::string(e.what()), ThrowingType::throwString);
+ }
+ break;
+ }
+ default:
+ QFAIL("Unknown ThrowingType::MoveCase");
+ };
+}
+#endif // QT_NO_EXCEPTIONS
+
QTEST_APPLESS_MAIN(tst_QArrayData)
#include "tst_qarraydata.moc"
diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/CMakeLists.txt b/tests/auto/corelib/tools/qatomicscopedvaluerollback/CMakeLists.txt
new file mode 100644
index 0000000000..b20e56421f
--- /dev/null
+++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qatomicscopedvaluerollback LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qatomicscopedvaluerollback
+ SOURCES
+ tst_qatomicscopedvaluerollback.cpp
+)
diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
new file mode 100644
index 0000000000..89bd1d7ff6
--- /dev/null
+++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qatomicscopedvaluerollback.h>
+
+#include <QTest>
+
+class tst_QAtomicScopedValueRollback : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void leavingScope();
+ void leavingScopeAfterCommit();
+ void rollbackToPreviousCommit();
+ void exceptions();
+ void earlyExitScope();
+private:
+ void earlyExitScope_helper(int exitpoint, std::atomic<int> &member);
+};
+
+void tst_QAtomicScopedValueRollback::leavingScope()
+{
+ QAtomicInt i = 0;
+ QBasicAtomicInteger<bool> b = false;
+ std::atomic<bool> b2 = false;
+ int x = 0, y = 42;
+ QBasicAtomicPointer<int> p = &x;
+
+ //test rollback on going out of scope
+ {
+ QAtomicScopedValueRollback ri(i);
+ QAtomicScopedValueRollback rb(b);
+ QAtomicScopedValueRollback rb2(b2, true);
+ QAtomicScopedValueRollback rp(p);
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(b2, true);
+ QCOMPARE(i.loadRelaxed(), 0);
+ QCOMPARE(p.loadRelaxed(), &x);
+ b.storeRelaxed(true);
+ i.storeRelaxed(1);
+ p.storeRelaxed(&y);
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i.loadRelaxed(), 1);
+ QCOMPARE(p.loadRelaxed(), &y);
+ }
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(b2, false);
+ QCOMPARE(i.loadRelaxed(), 0);
+ QCOMPARE(p.loadRelaxed(), &x);
+}
+
+void tst_QAtomicScopedValueRollback::leavingScopeAfterCommit()
+{
+ std::atomic<int> i = 0;
+ QAtomicInteger<bool> b = false;
+
+ //test rollback on going out of scope
+ {
+ QAtomicScopedValueRollback ri(i);
+ QAtomicScopedValueRollback rb(b);
+ QCOMPARE(b.loadRelaxed(), false);
+ QCOMPARE(i, 0);
+ b.storeRelaxed(true);
+ i = 1;
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i, 1);
+ ri.commit();
+ rb.commit();
+ }
+ QCOMPARE(b.loadRelaxed(), true);
+ QCOMPARE(i, 1);
+}
+
+void tst_QAtomicScopedValueRollback::rollbackToPreviousCommit()
+{
+ QBasicAtomicInt i = 0;
+ {
+ QAtomicScopedValueRollback ri(i);
+ i++;
+ ri.commit();
+ i++;
+ }
+ QCOMPARE(i.loadRelaxed(), 1);
+ {
+ QAtomicScopedValueRollback ri1(i);
+ i++;
+ ri1.commit();
+ i++;
+ ri1.commit();
+ i++;
+ }
+ QCOMPARE(i.loadRelaxed(), 3);
+}
+
+void tst_QAtomicScopedValueRollback::exceptions()
+{
+ std::atomic<bool> b = false;
+ bool caught = false;
+ QT_TRY
+ {
+ QAtomicScopedValueRollback rb(b);
+ b = true;
+ QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop
+ rb.commit(); //if Qt compiled without exceptions, true is committed
+ }
+ QT_CATCH(...)
+ {
+ caught = true;
+ }
+ QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise
+}
+
+void tst_QAtomicScopedValueRollback::earlyExitScope()
+{
+ QAtomicInt ai = 0;
+ std::atomic<int> aj = 0;
+ while (true) {
+ QAtomicScopedValueRollback ri(ai);
+ ++ai;
+ aj = ai.loadRelaxed();
+ if (ai.loadRelaxed() > 8) break;
+ ri.commit();
+ }
+ QCOMPARE(ai.loadRelaxed(), 8);
+ QCOMPARE(aj.load(), 9);
+
+ for (int i = 0; i < 5; ++i) {
+ aj = 1;
+ earlyExitScope_helper(i, aj);
+ QCOMPARE(aj.load(), 1 << i);
+ }
+}
+
+static void operator*=(std::atomic<int> &lhs, int rhs)
+{
+ int expected = lhs.load();
+ while (!lhs.compare_exchange_weak(expected, expected * rhs))
+ ;
+}
+
+void tst_QAtomicScopedValueRollback::earlyExitScope_helper(int exitpoint, std::atomic<int>& member)
+{
+ QAtomicScopedValueRollback r(member);
+ member *= 2;
+ if (exitpoint == 0)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 1)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 2)
+ return;
+ r.commit();
+ member *= 2;
+ if (exitpoint == 3)
+ return;
+ r.commit();
+}
+
+QTEST_MAIN(tst_QAtomicScopedValueRollback)
+#include "tst_qatomicscopedvaluerollback.moc"
diff --git a/tests/auto/corelib/tools/qbitarray/CMakeLists.txt b/tests/auto/corelib/tools/qbitarray/CMakeLists.txt
new file mode 100644
index 0000000000..ac3bd24bd5
--- /dev/null
+++ b/tests/auto/corelib/tools/qbitarray/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbitarray Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbitarray LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbitarray
+ SOURCES
+ tst_qbitarray.cpp
+ LIBRARIES
+ Qt::TestPrivate
+)
diff --git a/tests/auto/corelib/tools/qbitarray/qbitarray.pro b/tests/auto/corelib/tools/qbitarray/qbitarray.pro
deleted file mode 100644
index 1e7185b600..0000000000
--- a/tests/auto/corelib/tools/qbitarray/qbitarray.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qbitarray
-QT = core testlib
-SOURCES = tst_qbitarray.cpp
diff --git a/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp b/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
index 9a7c099228..f52a368aa9 100644
--- a/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
+++ b/tests/auto/corelib/tools/qbitarray/tst_qbitarray.cpp
@@ -1,47 +1,26 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QtTest/private/qcomparisontesthelper_p.h>
#include <QtCore/QBuffer>
#include <QtCore/QDataStream>
#include "qbitarray.h"
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qscopeguard.h>
+
/**
* Helper function to initialize a bitarray from a string
*/
static QBitArray QStringToQBitArray(const QString &str)
{
QBitArray ba;
- ba.resize(str.length());
+ ba.resize(str.size());
int i;
QChar tru('1');
- for (i = 0; i < str.length(); i++)
+ for (i = 0; i < str.size(); i++)
{
if (str.at(i) == tru)
{
@@ -51,10 +30,18 @@ static QBitArray QStringToQBitArray(const QString &str)
return ba;
}
+static QBitArray detached(QBitArray a)
+{
+ a.detach();
+ return a;
+}
+
class tst_QBitArray : public QObject
{
Q_OBJECT
private slots:
+ void compareCompiles();
+ void canHandleIntMaxBits();
void size_data();
void size();
void countBits_data();
@@ -68,12 +55,21 @@ private slots:
// operator &=
void operator_andeq_data();
void operator_andeq();
+ // operator &
+ void operator_and_data() { operator_andeq_data(); }
+ void operator_and();
// operator |=
void operator_oreq_data();
void operator_oreq();
+ // operator |
+ void operator_or_data() { operator_oreq_data(); }
+ void operator_or();
// operator ^=
void operator_xoreq_data();
void operator_xoreq();
+ // operator ^
+ void operator_xor_data() { operator_xoreq_data(); }
+ void operator_xor();
// operator ~
void operator_neg_data();
void operator_neg();
@@ -86,8 +82,64 @@ private slots:
void resize();
void fromBits_data();
void fromBits();
+
+ void toUInt32_data();
+ void toUInt32();
};
+void tst_QBitArray::compareCompiles()
+{
+ QTestPrivate::testEqualityOperatorsCompile<QBitArray>();
+}
+
+void tst_QBitArray::canHandleIntMaxBits()
+{
+ QElapsedTimer timer;
+ timer.start();
+ const auto print = qScopeGuard([&] {
+ qDebug("Function took %lldms", qlonglong(timer.elapsed()));
+ });
+
+ try {
+ constexpr qsizetype Size1 = sizeof(void*) > sizeof(int) ? qsizetype(INT_MAX) + 2 :
+ INT_MAX - 2;
+ constexpr qsizetype Size2 = Size1 + 2;
+
+ QBitArray ba(Size1, true);
+ QCOMPARE(ba.size(), Size1);
+ QCOMPARE(ba.at(Size1 - 1), true);
+
+ ba.resize(Size2);
+ QCOMPARE(ba.size(), Size2);
+ QCOMPARE(ba.at(Size1 - 1), true);
+ QCOMPARE(ba.at(Size1), false);
+ QCOMPARE(ba.at(Size2 - 1), false);
+
+ QByteArray serialized;
+ if constexpr (sizeof(void*) > sizeof(int)) {
+ QDataStream ds(&serialized, QIODevice::WriteOnly);
+ ds.setVersion(QDataStream::Qt_5_15);
+ ds << ba;
+ QCOMPARE(ds.status(), QDataStream::Status::SizeLimitExceeded);
+ serialized.clear();
+ }
+ {
+ QDataStream ds(&serialized, QIODevice::WriteOnly);
+ ds << ba;
+ QCOMPARE(ds.status(), QDataStream::Status::Ok);
+ }
+ {
+ QDataStream ds(serialized);
+ QBitArray ba2;
+ ds >> ba2;
+ QCOMPARE(ds.status(), QDataStream::Status::Ok);
+ QT_TEST_EQUALITY_OPS(ba, ba2, true);
+ }
+ } catch (const std::bad_alloc &) {
+ QSKIP("Failed to allocate sufficient memory");
+ }
+}
+
void tst_QBitArray::size_data()
{
//create the testtable instance and define the elements
@@ -147,7 +199,6 @@ void tst_QBitArray::countBits_data()
QTest::newRow("11111111111111111111111111111111") << QString("11111111111111111111111111111111") << 32 << 32;
QTest::newRow("11111111111111111111111111111111111111111111111111111111")
<< QString("11111111111111111111111111111111111111111111111111111111") << 56 << 56;
- QTest::newRow("00000000000000000000000000000000000") << QString("00000000000000000000000000000000000") << 35 << 0;
QTest::newRow("00000000000000000000000000000000") << QString("00000000000000000000000000000000") << 32 << 0;
QTest::newRow("00000000000000000000000000000000000000000000000000000000")
<< QString("00000000000000000000000000000000000000000000000000000000") << 56 << 0;
@@ -165,6 +216,8 @@ void tst_QBitArray::countBits()
bits.setBit(i);
}
+ QCOMPARE(bits.size(), numBits);
+ // NOLINTNEXTLINE(qt-port-to-std-compatible-api): We want to test count() and size()
QCOMPARE(bits.count(), numBits);
QCOMPARE(bits.count(true), onBits);
QCOMPARE(bits.count(false), numBits - onBits);
@@ -220,14 +273,20 @@ void tst_QBitArray::isEmpty()
QVERIFY(!a1.isEmpty());
QVERIFY(!a1.isNull());
QVERIFY(a1.size() == 2);
+
+ QT_TEST_EQUALITY_OPS(a1, a2, false);
+ QT_TEST_EQUALITY_OPS(a2, a3, false);
+ QT_TEST_EQUALITY_OPS(QBitArray(), QBitArray(), true);
+ a3 = a2;
+ QT_TEST_EQUALITY_OPS(a2, a3, true);
}
void tst_QBitArray::swap()
{
QBitArray b1 = QStringToQBitArray("1"), b2 = QStringToQBitArray("10");
b1.swap(b2);
- QCOMPARE(b1,QStringToQBitArray("10"));
- QCOMPARE(b2,QStringToQBitArray("1"));
+ QT_TEST_EQUALITY_OPS(b1,QStringToQBitArray("10"), true);
+ QT_TEST_EQUALITY_OPS(b2,QStringToQBitArray("1"), true);
}
void tst_QBitArray::fill()
@@ -277,7 +336,7 @@ void tst_QBitArray::toggleBit()
input.toggleBit(index);
- QCOMPARE(input, res);
+ QT_TEST_EQUALITY_OPS(input, res, true);
}
void tst_QBitArray::operator_andeq_data()
@@ -322,9 +381,64 @@ void tst_QBitArray::operator_andeq()
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
- input1&=input2;
+ QBitArray result = input1;
+ result &= input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result &= std::move(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result &= detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2;
+ result &= input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result &= std::move(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result &= detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is idempotent
+ result &= result;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result &= std::move(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result &= detached(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+}
- QCOMPARE(input1, res);
+void tst_QBitArray::operator_and()
+{
+ QFETCH(QBitArray, input1);
+ QFETCH(QBitArray, input2);
+ QFETCH(QBitArray, res);
+
+ QBitArray result = input1 & input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 & QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 & detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2 & input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 & QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 & detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is idempotent
+ result = result & result;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = result & QBitArray(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = result & detached(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_oreq_data()
@@ -373,9 +487,64 @@ void tst_QBitArray::operator_oreq()
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
- input1|=input2;
+ QBitArray result = input1;
+ result |= input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result |= QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result |= detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2;
+ result |= input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result |= QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result |= detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is idempotent
+ result |= result;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result |= QBitArray(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result |= detached(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+}
+
+void tst_QBitArray::operator_or()
+{
+ QFETCH(QBitArray, input1);
+ QFETCH(QBitArray, input2);
+ QFETCH(QBitArray, res);
- QCOMPARE(input1, res);
+ QBitArray result = input1 | input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 | QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 | detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2 | input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 | QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 | detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is idempotent
+ result = result | result;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = result | QBitArray(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = result | detached(result);
+ QT_TEST_EQUALITY_OPS(result, res, true);
}
void tst_QBitArray::operator_xoreq_data()
@@ -422,11 +591,102 @@ void tst_QBitArray::operator_xoreq()
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
- input1^=input2;
-
- QCOMPARE(input1, res);
+ QBitArray result = input1;
+ result ^= input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result ^= QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1;
+ result ^= detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2;
+ result ^= input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result ^= QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2;
+ result ^= detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // XORing with oneself is nilpotent
+ result = input1;
+ result ^= input1;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+ result = input1;
+ result ^= QBitArray(result);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+ result = input1;
+ result ^= detached(result);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+
+ result = input2;
+ result ^= input2;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+ result = input2;
+ result ^= QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+ result = input2;
+ result ^= detached(input2);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+
+ result = res;
+ result ^= res;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
+ result = res;
+ result ^= QBitArray(res);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
+ result = res;
+ result ^= detached(res);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
}
+void tst_QBitArray::operator_xor()
+{
+ QFETCH(QBitArray, input1);
+ QFETCH(QBitArray, input2);
+ QFETCH(QBitArray, res);
+
+ QBitArray result = input1 ^ input2;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 ^ QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input1 ^ detached(input2);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // operation is commutative
+ result = input2 ^ input1;
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 ^ QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+ result = input2 ^ detached(input1);
+ QT_TEST_EQUALITY_OPS(result, res, true);
+
+ // XORing with oneself is nilpotent
+ result = input1 ^ input1;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+ result = input1 ^ QBitArray(input1);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+ result = input1 ^ detached(input1);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input1.size()), true);
+
+ result = input2 ^ input2;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+ result = input2 ^ QBitArray(input2);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+ result = input2 ^ detached(input2);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(input2.size()), true);
+
+ result = res ^ res;
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
+ result = res ^ QBitArray(res);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
+ result = res ^ detached(res);
+ QT_TEST_EQUALITY_OPS(result, QBitArray(res.size()), true);
+}
void tst_QBitArray::operator_neg_data()
{
@@ -474,7 +734,8 @@ void tst_QBitArray::operator_neg()
input = ~input;
- QCOMPARE(input, res);
+ QT_TEST_EQUALITY_OPS(input, res, true);
+ QT_TEST_EQUALITY_OPS(~~input, res, true); // performs two in-place negations
}
void tst_QBitArray::datastream_data()
@@ -494,7 +755,6 @@ void tst_QBitArray::datastream_data()
QTest::newRow("11111111111111111111111111111111") << QString("11111111111111111111111111111111") << 32 << 32;
QTest::newRow("11111111111111111111111111111111111111111111111111111111")
<< QString("11111111111111111111111111111111111111111111111111111111") << 56 << 56;
- QTest::newRow("00000000000000000000000000000000000") << QString("00000000000000000000000000000000000") << 35 << 0;
QTest::newRow("00000000000000000000000000000000") << QString("00000000000000000000000000000000") << 32 << 0;
QTest::newRow("00000000000000000000000000000000000000000000000000000000")
<< QString("00000000000000000000000000000000000000000000000000000000") << 56 << 0;
@@ -516,7 +776,7 @@ void tst_QBitArray::datastream()
bits.setBit(i);
}
- QCOMPARE(bits.count(), numBits);
+ QCOMPARE(bits.size(), numBits);
QCOMPARE(bits.count(true), onBits);
QCOMPARE(bits.count(false), numBits - onBits);
@@ -531,19 +791,19 @@ void tst_QBitArray::datastream()
QBitArray array1, array2, array3;
stream2 >> array1 >> array2 >> array3;
- QCOMPARE(array1.count(), numBits);
+ QCOMPARE(array1.size(), numBits);
QCOMPARE(array1.count(true), onBits);
QCOMPARE(array1.count(false), numBits - onBits);
- QCOMPARE(array1, bits);
- QCOMPARE(array2, bits);
- QCOMPARE(array3, bits);
+ QT_TEST_EQUALITY_OPS(array1, bits, true);
+ QT_TEST_EQUALITY_OPS(array2, bits, true);
+ QT_TEST_EQUALITY_OPS(array3, bits, true);
}
void tst_QBitArray::invertOnNull() const
{
QBitArray a;
- QCOMPARE(a = ~a, QBitArray());
+ QT_TEST_EQUALITY_OPS(a = ~a, QBitArray(), true);
}
void tst_QBitArray::operator_noteq_data()
@@ -584,7 +844,7 @@ void tst_QBitArray::operator_noteq()
QFETCH(bool, res);
bool b = input1 != input2;
- QCOMPARE(b, res);
+ QT_TEST_EQUALITY_OPS(b, res, true);
}
void tst_QBitArray::resize()
@@ -593,22 +853,22 @@ void tst_QBitArray::resize()
QBitArray a = QStringToQBitArray(QString("11"));
a.resize(10);
QVERIFY(a.size() == 10);
- QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("1100000000")), true);
a.setBit(9);
a.resize(9);
// now the bit in a should have been gone:
- QCOMPARE( a, QStringToQBitArray(QString("110000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("110000000")), true);
// grow the array back and check the new bit
a.resize(10);
- QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( a, QStringToQBitArray(QString("1100000000")), true);
// other test with and
a.resize(9);
QBitArray b = QStringToQBitArray(QString("1111111111"));
b &= a;
- QCOMPARE( b, QStringToQBitArray(QString("1100000000")) );
+ QT_TEST_EQUALITY_OPS( b, QStringToQBitArray(QString("1100000000")), true);
}
@@ -662,9 +922,99 @@ void tst_QBitArray::fromBits()
QFETCH(QBitArray, expected);
QBitArray fromBits = QBitArray::fromBits(data, size);
- QCOMPARE(fromBits, expected);
+ QT_TEST_EQUALITY_OPS(fromBits, expected, true);
- QCOMPARE(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected);
+ QT_TEST_EQUALITY_OPS(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected, true);
+}
+
+void tst_QBitArray::toUInt32_data()
+{
+ QTest::addColumn<QBitArray>("data");
+ QTest::addColumn<int>("endianness");
+ QTest::addColumn<bool>("check");
+ QTest::addColumn<quint32>("result");
+
+ QTest::newRow("ctor") << QBitArray()
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(0);
+
+ QTest::newRow("empty") << QBitArray(0)
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(0);
+
+ QTest::newRow("LittleEndian4") << QStringToQBitArray(QString("0111"))
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(14);
+
+ QTest::newRow("BigEndian4") << QStringToQBitArray(QString("0111"))
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << true
+ << quint32(7);
+
+ QTest::newRow("LittleEndian8") << QStringToQBitArray(QString("01111111"))
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(254);
+
+ QTest::newRow("BigEndian8") << QStringToQBitArray(QString("01111111"))
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << true
+ << quint32(127);
+
+ QTest::newRow("LittleEndian16") << QStringToQBitArray(QString("0111111111111111"))
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(65534);
+
+ QTest::newRow("BigEndian16") << QStringToQBitArray(QString("0111111111111111"))
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << true
+ << quint32(32767);
+
+ QTest::newRow("LittleEndian31") << QBitArray(31, true)
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(2147483647);
+
+ QTest::newRow("BigEndian31") << QBitArray(31, true)
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << true
+ << quint32(2147483647);
+
+ QTest::newRow("LittleEndian32") << QBitArray(32, true)
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << true
+ << quint32(4294967295);
+
+ QTest::newRow("BigEndian32") << QBitArray(32, true)
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << true
+ << quint32(4294967295);
+
+ QTest::newRow("LittleEndian33") << QBitArray(33, true)
+ << static_cast<int>(QSysInfo::Endian::LittleEndian)
+ << false
+ << quint32(0);
+
+ QTest::newRow("BigEndian33") << QBitArray(33, true)
+ << static_cast<int>(QSysInfo::Endian::BigEndian)
+ << false
+ << quint32(0);
+}
+
+void tst_QBitArray::toUInt32()
+{
+ QFETCH(QBitArray, data);
+ QFETCH(int, endianness);
+ QFETCH(bool, check);
+ QFETCH(quint32, result);
+ bool ok = false;
+
+ QCOMPARE(data.toUInt32(static_cast<QSysInfo::Endian>(endianness), &ok), result);
+ QCOMPARE(ok, check);
}
QTEST_APPLESS_MAIN(tst_QBitArray)
diff --git a/tests/auto/corelib/tools/qcache/CMakeLists.txt b/tests/auto/corelib/tools/qcache/CMakeLists.txt
new file mode 100644
index 0000000000..8ffe942d70
--- /dev/null
+++ b/tests/auto/corelib/tools/qcache/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qcache Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcache LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qcache
+ SOURCES
+ tst_qcache.cpp
+)
diff --git a/tests/auto/corelib/tools/qcache/qcache.pro b/tests/auto/corelib/tools/qcache/qcache.pro
deleted file mode 100644
index 07488ef40f..0000000000
--- a/tests/auto/corelib/tools/qcache/qcache.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qcache
-QT = core testlib
-SOURCES = tst_qcache.cpp
diff --git a/tests/auto/corelib/tools/qcache/tst_qcache.cpp b/tests/auto/corelib/tools/qcache/tst_qcache.cpp
index d880953c1c..5fccb8f1d0 100644
--- a/tests/auto/corelib/tools/qcache/tst_qcache.cpp
+++ b/tests/auto/corelib/tools/qcache/tst_qcache.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <qcache.h>
@@ -37,6 +12,7 @@ public slots:
void initTestCase();
void cleanupTestCase();
private slots:
+ void empty();
void maxCost();
void setMaxCost();
void totalCost();
@@ -47,6 +23,10 @@ private slots:
void remove();
void take();
void axioms_on_key_type();
+ void largeCache();
+ void internalChainOrderAfterEntryUpdate();
+ void emplaceLowerCost();
+ void trimWithMovingAcrossSpans();
};
@@ -72,6 +52,21 @@ void tst_QCache::cleanupTestCase()
QCOMPARE(Foo::count, 0);
}
+void tst_QCache::empty()
+{
+ QCache<int, int> cache;
+ QCOMPARE(cache.size(), 0);
+ QCOMPARE(cache.count(), 0);
+ QVERIFY(cache.isEmpty());
+ QVERIFY(!cache.contains(1));
+ QCOMPARE(cache.keys().size(), 0);
+ QCOMPARE(cache.take(1), nullptr);
+ QVERIFY(!cache.remove(1));
+ QCOMPARE(cache.object(1), nullptr);
+ QCOMPARE(cache[1], nullptr);
+ QCOMPARE(cache.totalCost(), 0);
+}
+
void tst_QCache::maxCost()
{
QCache<QString, int> cache1, cache2(100), cache3(200), cache4(-50);
@@ -356,6 +351,7 @@ struct KeyType
int foo;
KeyType(int x) : foo(x) {}
+ constexpr KeyType(const KeyType &o) noexcept : foo(o.foo) {}
private:
KeyType &operator=(const KeyType &);
@@ -377,7 +373,7 @@ bool operator==(const KeyType &key1, const KeyType &key2)
return key1.foo == key2.foo;
}
-uint qHash(const KeyType &key)
+size_t qHash(const KeyType &key)
{
return qHash(key.foo);
}
@@ -398,5 +394,115 @@ void tst_QCache::axioms_on_key_type()
QVERIFY(sizeof(QHash<int, int>) == sizeof(void *));
}
+void tst_QCache::largeCache()
+{
+ QCache<int, int> cache;
+ cache.setMaxCost(500);
+ for (int i = 0; i < 1000; ++i) {
+ for (int j = 0; j < qMax(0, i - 500); ++j)
+ QVERIFY(!cache.contains(j));
+ for (int j = qMax(0, i - 500); j < i; ++j)
+ QVERIFY(cache.contains(j));
+ cache.insert(i, new int);
+ }
+ cache.clear();
+ QVERIFY(cache.size() == 0);
+}
+
+// The internal chain could lose track of some objects.
+// Make sure it doesn't happen again.
+void tst_QCache::internalChainOrderAfterEntryUpdate()
+{
+ QCache<QString, int> cache;
+ cache.setMaxCost(20);
+ cache.insert(QString::number(1), new int, 1);
+ cache.insert(QString::number(2), new int, 1);
+ cache.insert(QString::number(1), new int, 1);
+ // If the chain is still 'in order' then setting maxCost == 0 should
+ // a. not crash, and
+ // b. remove all the elements in the QHash
+ cache.setMaxCost(0);
+ QCOMPARE(cache.size(), 0);
+}
+
+void tst_QCache::emplaceLowerCost()
+{
+ QCache<QString, int> cache;
+ cache.setMaxCost(5);
+ cache.insert("a", new int, 3); // insert high cost
+ cache.insert("a", new int, 1); // and then exchange it with a lower-cost object
+ QCOMPARE(cache.totalCost(), 1);
+ cache.remove("a"); // then remove the object
+ // The cache should now have a cost == 0 and be empty.
+ QCOMPARE(cache.totalCost(), 0);
+ QVERIFY(cache.isEmpty());
+}
+
+struct TrivialHashType {
+ int i = -1;
+ size_t hash = 0;
+
+ TrivialHashType(int i, size_t hash) : i(i), hash(hash) {}
+ TrivialHashType(const TrivialHashType &o) noexcept = default;
+ TrivialHashType &operator=(const TrivialHashType &o) noexcept = default;
+ TrivialHashType(TrivialHashType &&o) noexcept : i(o.i), hash(o.hash) {
+ o.i = -1;
+ o.hash = 0;
+ }
+ TrivialHashType &operator=(TrivialHashType &&o) noexcept {
+ i = o.i;
+ hash = o.hash;
+ o.i = -1;
+ o.hash = 0;
+ return *this;
+ }
+
+
+ friend bool operator==(const TrivialHashType &lhs, const TrivialHashType &rhs)
+ {
+ return lhs.i == rhs.i;
+ }
+};
+quint64 qHash(TrivialHashType t, size_t seed = 0)
+{
+ Q_UNUSED(seed);
+ return t.hash;
+}
+
+// During trim(), if the Node we have a pointer to in the function is moved
+// to another span in the hash table, our pointer would end up pointing to
+// garbage memory. Test that this no longer happens
+void tst_QCache::trimWithMovingAcrossSpans()
+{
+ qsizetype numBuckets = [](){
+ QHash<int, int> h;
+ h.reserve(1);
+ // Beholden to QHash internals:
+ return h.capacity() << 1;
+ }();
+
+ QCache<TrivialHashType, int> cache;
+ cache.setMaxCost(1000);
+
+ auto lastBucketInSpan = size_t(numBuckets - 1);
+ // If this fails then the test is no longer valid
+ QCOMPARE(QHashPrivate::GrowthPolicy::bucketForHash(numBuckets, lastBucketInSpan),
+ lastBucketInSpan);
+
+ // Pad some space so we have two spans:
+ for (int i = 2; i < numBuckets; ++i)
+ cache.insert({i, 0}, nullptr);
+
+ // These two are vying for the last bucket in the first span,
+ // when '0' is deleted, '1' is moved across the span boundary,
+ // invalidating any pointer to its Node.
+ cache.insert({0, lastBucketInSpan}, nullptr);
+ cache.insert({1, lastBucketInSpan}, nullptr);
+
+ QCOMPARE(cache.size(), numBuckets);
+ cache.setMaxCost(0);
+ QCOMPARE(cache.size(), 0);
+}
+
QTEST_APPLESS_MAIN(tst_QCache)
#include "tst_qcache.moc"
diff --git a/tests/auto/corelib/tools/qcommandlineparser/CMakeLists.txt b/tests/auto/corelib/tools/qcommandlineparser/CMakeLists.txt
new file mode 100644
index 0000000000..5aa8bd2500
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qcommandlineparser Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcommandlineparser LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qcommandlineparser
+ SOURCES
+ tst_qcommandlineparser.cpp
+)
+add_subdirectory(testhelper)
+if(QT_FEATURE_process AND NOT ANDROID)
+ add_dependencies(tst_qcommandlineparser qcommandlineparser_test_helper)
+endif()
diff --git a/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro b/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro
deleted file mode 100644
index a9aedc4c0d..0000000000
--- a/tests/auto/corelib/tools/qcommandlineparser/qcommandlineparser.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += tst_qcommandlineparser.pro testhelper/qcommandlineparser_test_helper.pro
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/CMakeLists.txt b/tests/auto/corelib/tools/qcommandlineparser/testhelper/CMakeLists.txt
new file mode 100644
index 0000000000..20cec30a9c
--- /dev/null
+++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qcommandlineparser_test_helper Binary:
+#####################################################################
+
+qt_internal_add_executable(qcommandlineparser_test_helper
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ qcommandlineparser_test_helper.cpp
+)
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
index 513c811788..b5f178a3d1 100644
--- a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
+++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure@kde.org>
-** 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) 2013 David Faure <faure@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QDebug>
#include <QCoreApplication>
@@ -74,12 +49,6 @@ int main(int argc, char *argv[])
hiddenOption.setDescription(QStringLiteral("THIS SHOULD NEVER APPEAR"));
hiddenOption.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(hiddenOption);
-#if QT_DEPRECATED_SINCE(5, 8)
- QCommandLineOption hiddenOption2(QStringList() << QStringLiteral("hidden2"));
- hiddenOption2.setDescription(QStringLiteral("NEITHER SHOULD THIS"));
- hiddenOption2.setHidden(true);
- parser.addOption(hiddenOption2);
-#endif
// This program supports different options depending on the "command" (first argument).
// Call parse() to find out the positional arguments.
@@ -97,6 +66,13 @@ int main(int argc, char *argv[])
parser.process(app);
const QString size = parser.value("size");
printf("Resizing %s to %s and saving to %s\n", qPrintable(parser.value("load")), qPrintable(size), qPrintable(parser.value("o")));
+ } else if (command == "long") {
+ // A very long option (QTBUG-79926)
+ QCommandLineOption longOption(QStringList{QStringLiteral("looooooooooooong-option"), QStringLiteral("looooong-opt-alias")});
+ longOption.setDescription(QStringLiteral("Short description"));
+ longOption.setValueName(QStringLiteral("looooooooooooong-value-name"));
+ parser.addOption(longOption);
+ parser.process(app);
} else {
// Call process again, to handle unknown options this time.
parser.process(app);
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro
deleted file mode 100644
index 5020658835..0000000000
--- a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += cmdline
-QT = core
-DESTDIR = ./
-
-SOURCES += qcommandlineparser_test_helper.cpp
diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
index 1e87c76d2f..812cf2d1b3 100644
--- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
+++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
@@ -1,32 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 David Faure <faure@kde.org>
-** 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>
+// Copyright (C) 2021 David Faure <faure@kde.org>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
#include <QtCore/QCommandLineParser>
Q_DECLARE_METATYPE(char**)
@@ -63,6 +42,7 @@ private slots:
void testDefaultValue();
void testProcessNotCalled();
void testEmptyArgsList();
+ void testNoApplication();
void testMissingOptionValue();
void testStdinArgument_data();
void testStdinArgument();
@@ -78,6 +58,7 @@ private slots:
void testUnknownOption();
void testHelpAll_data();
void testHelpAll();
+ void testVeryLongOptionNames();
};
static char *empty_argv[] = { 0 };
@@ -145,6 +126,7 @@ void tst_QCommandLineParser::testBooleanOption()
QVERIFY(parser.parse(args));
QCOMPARE(parser.optionNames(), expectedOptionNames);
QCOMPARE(parser.isSet("b"), expectedIsSet);
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not expecting values: \"b\"");
QCOMPARE(parser.values("b"), QStringList());
QCOMPARE(parser.positionalArguments(), QStringList());
// Should warn on typos
@@ -182,6 +164,7 @@ void tst_QCommandLineParser::testOptionsAndPositional()
QVERIFY(parser.parse(args));
QCOMPARE(parser.optionNames(), expectedOptionNames);
QCOMPARE(parser.isSet("b"), expectedIsSet);
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not expecting values: \"b\"");
QCOMPARE(parser.values("b"), QStringList());
QCOMPARE(parser.positionalArguments(), expectedPositionalArguments);
}
@@ -380,6 +363,7 @@ void tst_QCommandLineParser::testProcessNotCalled()
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before isSet");
QVERIFY(!parser.isSet("b"));
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before values");
+ QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not expecting values: \"b\"");
QCOMPARE(parser.values("b"), QStringList());
}
@@ -391,6 +375,34 @@ void tst_QCommandLineParser::testEmptyArgsList()
QVERIFY(!parser.parse(QStringList())); // invalid call, argv[0] is missing
}
+void tst_QCommandLineParser::testNoApplication()
+{
+ QCommandLineOption option(QStringLiteral("param"), QStringLiteral("Pass parameter to the backend."));
+ option.setValueName("key=value");
+ QCommandLineParser parser;
+ QVERIFY(parser.addOption(option));
+ {
+ QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1"));
+ QVERIFY(parser.isSet("param"));
+ QCOMPARE(parser.values("param"), QStringList() << "key1=value1");
+ QCOMPARE(parser.value("param"), QString("key1=value1"));
+ }
+ {
+ QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1" << "--param" << "key2=value2"));
+ QVERIFY(parser.isSet("param"));
+ QCOMPARE(parser.values("param"), QStringList() << "key1=value1" << "key2=value2");
+ QCOMPARE(parser.value("param"), QString("key2=value2"));
+ }
+
+ const QString expected =
+ "Usage: <executable_name> [options]\n"
+ "\n"
+ "Options:\n"
+ " --param <key=value> Pass parameter to the backend.\n";
+
+ QCOMPARE(parser.helpText(), expected);
+}
+
void tst_QCommandLineParser::testMissingOptionValue()
{
QCoreApplication app(empty_argc, empty_argv);
@@ -439,37 +451,40 @@ void tst_QCommandLineParser::testSingleDashWordOptionModes_data()
QTest::addColumn<QStringList>("commandLine");
QTest::addColumn<QStringList>("expectedOptionNames");
QTest::addColumn<QStringList>("expectedOptionValues");
+ QTest::addColumn<QStringList>("invalidOptionValues");
QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc" << "val")
- << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
+ << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val")
+ << (QStringList() << "a" << "b");
QTest::newRow("collapsed_with_equalsign_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc=val")
- << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
+ << (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val")
+ << (QStringList() << "a" << "b");
QTest::newRow("collapsed_explicit_longoption") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("--nn")
- << QStringList("nn") << QStringList();
+ << QStringList("nn") << QStringList() << QStringList();
QTest::newRow("collapsed_longoption_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "--abc" << "val")
- << QStringList("abc") << QStringList("val");
+ << QStringList("abc") << QStringList("val") << QStringList();
QTest::newRow("compiler") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("-cab")
- << QStringList("c") << QStringList("ab");
+ << QStringList("c") << QStringList("ab") << QStringList();
QTest::newRow("compiler_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
- << QStringList("c") << QStringList("val");
+ << QStringList("c") << QStringList("val") << QStringList();
QTest::newRow("implicitlylong") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc" << "val")
- << QStringList("abc") << QStringList("val");
+ << QStringList("abc") << QStringList("val") << QStringList();
QTest::newRow("implicitlylong_equal") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc=val")
- << QStringList("abc") << QStringList("val");
+ << QStringList("abc") << QStringList("val") << QStringList();
QTest::newRow("implicitlylong_longoption") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--nn")
- << QStringList("nn") << QStringList();
+ << QStringList("nn") << QStringList() << QStringList();
QTest::newRow("implicitlylong_longoption_value") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--abc" << "val")
- << QStringList("abc") << QStringList("val");
+ << QStringList("abc") << QStringList("val") << QStringList();
QTest::newRow("implicitlylong_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
- << QStringList("c") << QStringList("val");
+ << QStringList("c") << QStringList("val") << QStringList();
QTest::newRow("forceshort_detached") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I" << "45")
- << QStringList("I") << QStringList("45");
+ << QStringList("I") << QStringList("45") << QStringList();
QTest::newRow("forceshort_attached") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I46")
- << QStringList("I") << QStringList("46");
+ << QStringList("I") << QStringList("46") << QStringList();
QTest::newRow("forceshort_mixed") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I45" << "-nn")
- << (QStringList() << "I" << "nn") << QStringList("45");
+ << (QStringList() << "I" << "nn") << QStringList("45") << QStringList();
}
void tst_QCommandLineParser::testSingleDashWordOptionModes()
@@ -478,6 +493,7 @@ void tst_QCommandLineParser::testSingleDashWordOptionModes()
QFETCH(QStringList, commandLine);
QFETCH(QStringList, expectedOptionNames);
QFETCH(QStringList, expectedOptionValues);
+ QFETCH(QStringList, invalidOptionValues);
commandLine.prepend("tst_QCommandLineParser");
@@ -494,14 +510,19 @@ void tst_QCommandLineParser::testSingleDashWordOptionModes()
QVERIFY(parser.addOption(forceShort));
QVERIFY(parser.parse(commandLine));
QCOMPARE(parser.optionNames(), expectedOptionNames);
- for (int i = 0; i < expectedOptionValues.count(); ++i)
- QCOMPARE(parser.value(parser.optionNames().at(i)), expectedOptionValues.at(i));
+ for (int i = 0; i < expectedOptionValues.size(); ++i) {
+ const QString option = parser.optionNames().at(i);
+ if (invalidOptionValues.contains(option)) {
+ QByteArray msg = QLatin1String("QCommandLineParser: option not expecting values: \"%1\"").arg(option).toLatin1();
+ QTest::ignoreMessage(QtWarningMsg, msg.data());
+ }
+ QCOMPARE(parser.value(option), expectedOptionValues.at(i));
+ }
QCOMPARE(parser.unknownOptionNames(), QStringList());
}
void tst_QCommandLineParser::testCpp11StyleInitialization()
{
-#if defined(Q_COMPILER_UNIFORM_INIT)
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
@@ -515,19 +536,15 @@ void tst_QCommandLineParser::testCpp11StyleInitialization()
QVERIFY(parser.parse({"tst_QCommandLineParser", "-a", "-vvv", "--infile=in.txt"}));
QCOMPARE(parser.optionNames(), (QStringList{"a", "v", "v", "v", "infile"}));
QCOMPARE(parser.value("infile"), QString("in.txt"));
-#else
- QSKIP("This test requires C++11 uniform initialization support in the compiler.");
-#endif
}
void tst_QCommandLineParser::testVersionOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
-#else
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
-#endif
+#else
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
@@ -545,7 +562,7 @@ void tst_QCommandLineParser::testVersionOption()
static const char expectedOptionsHelp[] =
"Options:\n"
" -h, --help Displays help on commandline options.\n"
- " --help-all Displays help including Qt specific options.\n"
+ " --help-all Displays help, including generic Qt options.\n"
" -v, --version Displays version information.\n"
" --load <url> Load file from URL.\n"
" -o, --output <file> Set output file.\n"
@@ -592,10 +609,9 @@ void tst_QCommandLineParser::testHelpOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
-#else
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
-#endif
+#else
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QFETCH(QString, expectedHelpOutput);
@@ -640,7 +656,7 @@ void tst_QCommandLineParser::testQuoteEscaping()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
-#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
@@ -666,7 +682,7 @@ void tst_QCommandLineParser::testUnknownOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
-#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
@@ -717,7 +733,7 @@ void tst_QCommandLineParser::testHelpAll()
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#else
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#ifdef Q_OS_ANDROID
QSKIP("Deploying executable applications to file system on Android not supported.");
#endif
@@ -737,6 +753,37 @@ void tst_QCommandLineParser::testHelpAll()
#endif // QT_CONFIG(process)
}
+void tst_QCommandLineParser::testVeryLongOptionNames()
+{
+#if !QT_CONFIG(process)
+ QSKIP("This test requires QProcess support");
+#elif defined(Q_OS_ANDROID)
+ QSKIP("Deploying executable applications to file system on Android not supported.");
+#else
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QProcess process;
+ process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "long" << "--help");
+ QVERIFY(process.waitForFinished(5000));
+ QCOMPARE(process.exitStatus(), QProcess::NormalExit);
+ QString output = process.readAll();
+#ifdef Q_OS_WIN
+ output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
+#endif
+ const QStringList lines = output.split('\n');
+ const int last = lines.size() - 1;
+ // Let's not compare everything, just the final parts.
+ QCOMPARE(lines.at(last - 7), " cdefghijklmnopqrstuvwxyz");
+ QCOMPARE(lines.at(last - 6), " --looooooooooooong-option, --looooong-opt-alias <l Short description");
+ QCOMPARE(lines.at(last - 5), " ooooooooooooong-value-name>");
+ QCOMPARE(lines.at(last - 4), "");
+ QCOMPARE(lines.at(last - 3), "Arguments:");
+ QCOMPARE(lines.at(last - 2), " parsingMode The parsing mode to test.");
+ QCOMPARE(lines.at(last - 1), " command The command to execute.");
+
+#endif // QT_CONFIG(process)
+}
+
QTEST_APPLESS_MAIN(tst_QCommandLineParser)
#include "tst_qcommandlineparser.moc"
diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro
deleted file mode 100644
index 75b74bbf4d..0000000000
--- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qcommandlineparser
-QT = core testlib
-SOURCES = tst_qcommandlineparser.cpp
diff --git a/tests/auto/corelib/tools/qcontiguouscache/CMakeLists.txt b/tests/auto/corelib/tools/qcontiguouscache/CMakeLists.txt
new file mode 100644
index 0000000000..5c32c34023
--- /dev/null
+++ b/tests/auto/corelib/tools/qcontiguouscache/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qcontiguouscache Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcontiguouscache LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qcontiguouscache
+ SOURCES
+ tst_qcontiguouscache.cpp
+)
diff --git a/tests/auto/corelib/tools/qcontiguouscache/qcontiguouscache.pro b/tests/auto/corelib/tools/qcontiguouscache/qcontiguouscache.pro
deleted file mode 100644
index d79bd16c76..0000000000
--- a/tests/auto/corelib/tools/qcontiguouscache/qcontiguouscache.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qcontiguouscache
-QT = core testlib
-SOURCES = tst_qcontiguouscache.cpp
diff --git a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp
index f305d63d46..ca110b1240 100644
--- a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp
+++ b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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 <QObject>
#include <QTest>
@@ -75,20 +50,24 @@ void tst_QContiguousCache::empty()
{
QContiguousCache<int> c(10);
QCOMPARE(c.capacity(), 10);
+ QCOMPARE(c.size(), 0);
+ // NOLINTNEXTLINE(qt-port-to-std-compatible-api): Test both size() and count()
QCOMPARE(c.count(), 0);
QVERIFY(c.isEmpty());
c.append(1);
+ // NOLINTNEXTLINE(qt-port-to-std-compatible-api): Test both size() and count()
QCOMPARE(c.count(), 1);
+ QCOMPARE(c.size(), 1);
QVERIFY(!c.isEmpty());
c.clear();
QCOMPARE(c.capacity(), 10);
- QCOMPARE(c.count(), 0);
+ QCOMPARE(c.size(), 0);
QVERIFY(c.isEmpty());
c.prepend(1);
- QCOMPARE(c.count(), 1);
+ QCOMPARE(c.size(), 1);
QVERIFY(!c.isEmpty());
c.clear();
- QCOMPARE(c.count(), 0);
+ QCOMPARE(c.size(), 0);
QVERIFY(c.isEmpty());
QCOMPARE(c.capacity(), 10);
}
@@ -99,32 +78,32 @@ void tst_QContiguousCache::swap()
c1.append(1);
c1.swap(c2);
QCOMPARE(c1.capacity(), 100);
- QCOMPARE(c1.count(), 0 );
+ QCOMPARE(c1.size(), 0 );
QCOMPARE(c2.capacity(), 10 );
- QCOMPARE(c2.count(), 1 );
+ QCOMPARE(c2.size(), 1 );
}
void tst_QContiguousCache::append_data()
{
- QTest::addColumn<int>("start");
- QTest::addColumn<int>("count");
- QTest::addColumn<int>("cacheSize");
+ QTest::addColumn<qsizetype>("start");
+ QTest::addColumn<qsizetype>("count");
+ QTest::addColumn<qsizetype>("cacheSize");
QTest::addColumn<bool>("invalidIndexes");
- QTest::newRow("0+30[10]") << 0 << 30 << 10 << false;
- QTest::newRow("300+30[10]") << 300 << 30 << 10 << false;
- QTest::newRow("MAX-10+30[10]") << INT_MAX-10 << 30 << 10 << true;
+ QTest::newRow("0+30[10]") << qsizetype(0) << qsizetype(30) << qsizetype(10) << false;
+ QTest::newRow("300+30[10]") << qsizetype(300) << qsizetype(30) << qsizetype(10) << false;
+ QTest::newRow("MAX-10+30[10]") << std::numeric_limits<qsizetype>::max()-10 << qsizetype(30) << qsizetype(10) << true;
}
void tst_QContiguousCache::append()
{
- QFETCH(int, start);
- QFETCH(int, count);
- QFETCH(int, cacheSize);
+ QFETCH(qsizetype, start);
+ QFETCH(qsizetype, count);
+ QFETCH(qsizetype, cacheSize);
QFETCH(bool, invalidIndexes);
- int i, j;
- QContiguousCache<int> c(cacheSize);
+ qsizetype i, j;
+ QContiguousCache<qsizetype> c(cacheSize);
i = 1;
QCOMPARE(c.available(), cacheSize);
@@ -134,10 +113,10 @@ void tst_QContiguousCache::append()
c.insert(start, i++);
while (i < count) {
c.append(i);
- QCOMPARE(c.available(), qMax(0, cacheSize - i));
- QCOMPARE(c.first(), qMax(1, i-cacheSize+1));
+ QCOMPARE(c.available(), qMax(qsizetype(0), cacheSize - i));
+ QCOMPARE(c.first(), qMax(qsizetype(1), i-cacheSize+1));
QCOMPARE(c.last(), i);
- QCOMPARE(c.count(), qMin(i, cacheSize));
+ QCOMPARE(c.size(), qMin(i, cacheSize));
QCOMPARE(c.isFull(), i >= cacheSize);
i++;
}
@@ -150,7 +129,7 @@ void tst_QContiguousCache::append()
// test taking from end until empty.
for (j = 0; j < cacheSize; j++, i--) {
QCOMPARE(c.takeLast(), i-1);
- QCOMPARE(c.count(), cacheSize-j-1);
+ QCOMPARE(c.size(), cacheSize-j-1);
QCOMPARE(c.available(), j+1);
QVERIFY(!c.isFull());
QCOMPARE(c.isEmpty(), j==cacheSize-1);
@@ -188,7 +167,7 @@ void tst_QContiguousCache::prepend()
QCOMPARE(c.available(), qMax(0, cacheSize - i));
QCOMPARE(c.last(), qMax(1, i-cacheSize+1));
QCOMPARE(c.first(), i);
- QCOMPARE(c.count(), qMin(i, cacheSize));
+ QCOMPARE(c.size(), qMin(i, cacheSize));
QCOMPARE(c.isFull(), i >= cacheSize);
i++;
}
@@ -201,7 +180,7 @@ void tst_QContiguousCache::prepend()
// test taking from start until empty.
for (j = 0; j < cacheSize; j++, i--) {
QCOMPARE(c.takeFirst(), i-1);
- QCOMPARE(c.count(), cacheSize-j-1);
+ QCOMPARE(c.size(), cacheSize-j-1);
QCOMPARE(c.available(), j+1);
QVERIFY(!c.isFull());
QCOMPARE(c.isEmpty(), j==cacheSize-1);
@@ -321,7 +300,7 @@ void tst_QContiguousCache::setCapacity()
for (i = 280; i < 310; ++i)
contiguousCache.insert(i, i);
QCOMPARE(contiguousCache.capacity(), 100);
- QCOMPARE(contiguousCache.count(), 30);
+ QCOMPARE(contiguousCache.size(), 30);
QCOMPARE(contiguousCache.firstIndex(), 280);
QCOMPARE(contiguousCache.lastIndex(), 309);
@@ -333,7 +312,7 @@ void tst_QContiguousCache::setCapacity()
contiguousCache.setCapacity(150);
QCOMPARE(contiguousCache.capacity(), 150);
- QCOMPARE(contiguousCache.count(), 30);
+ QCOMPARE(contiguousCache.size(), 30);
QCOMPARE(contiguousCache.firstIndex(), 280);
QCOMPARE(contiguousCache.lastIndex(), 309);
@@ -345,7 +324,7 @@ void tst_QContiguousCache::setCapacity()
contiguousCache.setCapacity(20);
QCOMPARE(contiguousCache.capacity(), 20);
- QCOMPARE(contiguousCache.count(), 20);
+ QCOMPARE(contiguousCache.size(), 20);
QCOMPARE(contiguousCache.firstIndex(), 290);
QCOMPARE(contiguousCache.lastIndex(), 309);
diff --git a/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt b/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt
new file mode 100644
index 0000000000..8a0c08fcad
--- /dev/null
+++ b/tests/auto/corelib/tools/qcryptographichash/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qcryptographichash Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qcryptographichash LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qcryptographichash
+ SOURCES
+ tst_qcryptographichash.cpp
+ TESTDATA ${test_data}
+)
+
+if(QT_FEATURE_sanitize_address)
+ set_property(TEST tst_qcryptographichash APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000")
+endif()
diff --git a/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro b/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro
deleted file mode 100644
index 8d3957a524..0000000000
--- a/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qcryptographichash
-QT = core testlib
-SOURCES = tst_qcryptographichash.cpp
-
-TESTDATA += data/*
-
-android:!android-embedded {
- RESOURCES += \
- testdata.qrc
-}
diff --git a/tests/auto/corelib/tools/qcryptographichash/testdata.qrc b/tests/auto/corelib/tools/qcryptographichash/testdata.qrc
deleted file mode 100644
index 8f7bcea63c..0000000000
--- a/tests/auto/corelib/tools/qcryptographichash/testdata.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>data/2c1517dad3678f03917f15849b052fd5.md5</file>
- <file>data/d41d8cd98f00b204e9800998ecf8427e.md5</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp
index 3eef7631c8..c08afd67c4 100644
--- a/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp
+++ b/tests/auto/corelib/tools/qcryptographichash/tst_qcryptographichash.cpp
@@ -1,36 +1,15 @@
-/****************************************************************************
-**
-** 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 <QtCore/QCoreApplication>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QScopeGuard>
+#include <QCryptographicHash>
#include <QtCore/QMetaEnum>
+#include <thread>
+
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
class tst_QCryptographicHash : public QObject
@@ -44,9 +23,25 @@ private slots:
void sha1();
void sha3_data();
void sha3();
+ void keccak();
+ void keccak_data();
+ void blake2_data();
+ void blake2();
void files_data();
void files();
+ void hashLength_data();
void hashLength();
+ void addDataAcceptsNullByteArrayView_data() { hashLength_data(); }
+ void addDataAcceptsNullByteArrayView();
+ void move();
+ void swap();
+ // keep last
+ void moreThan4GiBOfData_data();
+ void moreThan4GiBOfData();
+ void keccakBufferOverflow();
+private:
+ void ensureLargeData();
+ std::vector<char> large;
};
void tst_QCryptographicHash::repeated_result_data()
@@ -60,19 +55,23 @@ void tst_QCryptographicHash::repeated_result()
QCryptographicHash::Algorithm _algo = QCryptographicHash::Algorithm(algo);
QCryptographicHash hash(_algo);
+ QCOMPARE_EQ(hash.algorithm(), _algo);
+
QFETCH(QByteArray, first);
hash.addData(first);
QFETCH(QByteArray, hash_first);
- QByteArray result = hash.result();
+ QByteArrayView result = hash.resultView();
QCOMPARE(result, hash_first);
+ QCOMPARE(result, hash.resultView());
QCOMPARE(result, hash.result());
hash.reset();
hash.addData(first);
- result = hash.result();
+ result = hash.resultView();
QCOMPARE(result, hash_first);
QCOMPARE(result, hash.result());
+ QCOMPARE(result, hash.resultView());
}
void tst_QCryptographicHash::intermediary_result_data()
@@ -153,6 +152,27 @@ void tst_QCryptographicHash::intermediary_result_data()
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("B751850B1A57168A5693CD924B6B096E08F621827444F70D884F5D0240D2712E10E116E9192AF3C91A7EC57647E3934057340B4CF408D5A56592F8274EEC53F0")
<< QByteArray::fromHex("BB582DA40D15399ACF62AFCBBD6CFC9EE1DD5129B1EF9935DD3B21668F1A73D7841018BE3B13F281C3A8E9DA7EDB60F57B9F9F1C04033DF4CE3654B7B2ADB310");
+
+ QTest::newRow("keccak_224_abc_abc")
+ << int(QCryptographicHash::Keccak_224)
+ << QByteArray("abc") << QByteArray("abc")
+ << QByteArray::fromHex("c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8")
+ << QByteArray::fromHex("048330e7c7c8b4a41ab713b3a6f958d77b8cf3ee969930f1584dd550");
+ QTest::newRow("keccak_256_abc_abc")
+ << int(QCryptographicHash::Keccak_256)
+ << QByteArray("abc") << QByteArray("abc")
+ << QByteArray::fromHex("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
+ << QByteArray::fromHex("9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21");
+ QTest::newRow("keccak_384_abc_abc")
+ << int(QCryptographicHash::Keccak_384)
+ << QByteArray("abc") << QByteArray("abc")
+ << QByteArray::fromHex("f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e")
+ << QByteArray::fromHex("d733b87d392d270889d3da23ae113f349e25574b445f319cde4cd3f877c753e9e3c65980421339b3a131457ff393939f");
+ QTest::newRow("keccak_512_abc_abc")
+ << int(QCryptographicHash::Keccak_512)
+ << QByteArray("abc") << QByteArray("abc")
+ << QByteArray::fromHex("18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96")
+ << QByteArray::fromHex("a7c392d2a42155761ca76bddde1c47d55486b007edf465397bfb9dfa74d11c8f0d7c86cd29415283f1b5e7f655cec25b869c9e9c33a8986f0b38542fb12bfb93");
}
void tst_QCryptographicHash::intermediary_result()
@@ -165,16 +185,14 @@ void tst_QCryptographicHash::intermediary_result()
hash.addData(first);
QFETCH(QByteArray, hash_first);
- QByteArray result = hash.result();
- QCOMPARE(result, hash_first);
+ QCOMPARE(hash.resultView(), hash_first);
// don't reset
QFETCH(QByteArray, second);
QFETCH(QByteArray, hash_firstsecond);
hash.addData(second);
- result = hash.result();
- QCOMPARE(result, hash_firstsecond);
+ QCOMPARE(hash.resultView(), hash_firstsecond);
hash.reset();
}
@@ -195,10 +213,7 @@ void tst_QCryptographicHash::sha1()
// SHA1(A million repetitions of "a") =
// 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
- QByteArray as;
- for (int i = 0; i < 1000000; ++i)
- as += 'a';
- QCOMPARE(QCryptographicHash::hash(as, QCryptographicHash::Sha1).toHex().toUpper(),
+ QCOMPARE(QCryptographicHash::hash(QByteArray(1'000'000, 'a'), QCryptographicHash::Sha1).toHex().toUpper(),
QByteArray("34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"));
}
@@ -264,6 +279,172 @@ void tst_QCryptographicHash::sha3()
QCOMPARE(result, expectedResult);
}
+void tst_QCryptographicHash::keccak_data()
+{
+ QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QByteArray>("expectedResult");
+
+#define ROW(Tag, Algorithm, Input, Result) \
+ QTest::newRow(Tag) << Algorithm << QByteArrayLiteral(Input) << QByteArray::fromHex(Result)
+
+ ROW("keccak_224_pangram",
+ QCryptographicHash::Keccak_224,
+ "The quick brown fox jumps over the lazy dog",
+ "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe");
+
+ ROW("keccak_224_pangram_dot",
+ QCryptographicHash::Keccak_224,
+ "The quick brown fox jumps over the lazy dog.",
+ "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab");
+
+ ROW("keccak_256_pangram",
+ QCryptographicHash::Keccak_256,
+ "The quick brown fox jumps over the lazy dog",
+ "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15");
+
+ ROW("keccak_256_pangram_dot",
+ QCryptographicHash::Keccak_256,
+ "The quick brown fox jumps over the lazy dog.",
+ "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d");
+
+ ROW("keccak_384_pangram",
+ QCryptographicHash::Keccak_384,
+ "The quick brown fox jumps over the lazy dog",
+ "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3");
+
+ ROW("keccak_384_pangram_dot",
+ QCryptographicHash::Keccak_384,
+ "The quick brown fox jumps over the lazy dog.",
+ "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b");
+
+ ROW("skeccak_512_pangram",
+ QCryptographicHash::Keccak_512,
+ "The quick brown fox jumps over the lazy dog",
+ "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609");
+
+ ROW("keccak_512_pangram_dot",
+ QCryptographicHash::Keccak_512,
+ "The quick brown fox jumps over the lazy dog.",
+ "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760");
+
+#undef ROW
+}
+
+void tst_QCryptographicHash::keccak()
+{
+ QFETCH(QCryptographicHash::Algorithm, algorithm);
+ QFETCH(QByteArray, data);
+ QFETCH(QByteArray, expectedResult);
+
+ const auto result = QCryptographicHash::hash(data, algorithm);
+ QCOMPARE(result, expectedResult);
+}
+
+void tst_QCryptographicHash::blake2_data()
+{
+ QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QByteArray>("expectedResult");
+
+#define ROW(Tag, Algorithm, Input, Result) \
+ QTest::newRow(Tag) << Algorithm << QByteArrayLiteral(Input) << QByteArray::fromHex(Result)
+
+ // BLAKE2b
+ ROW("blake2b_160_pangram",
+ QCryptographicHash::Blake2b_160,
+ "The quick brown fox jumps over the lazy dog",
+ "3c523ed102ab45a37d54f5610d5a983162fde84f");
+
+ ROW("blake2b_160_pangram_dot",
+ QCryptographicHash::Blake2b_160,
+ "The quick brown fox jumps over the lazy dog.",
+ "d0c8bb0bdd830296d1d4f4348176699ccccc16bb");
+
+ ROW("blake2b_256_pangram",
+ QCryptographicHash::Blake2b_256,
+ "The quick brown fox jumps over the lazy dog",
+ "01718cec35cd3d796dd00020e0bfecb473ad23457d063b75eff29c0ffa2e58a9");
+
+ ROW("blake2b_256_pangram_dot",
+ QCryptographicHash::Blake2b_256,
+ "The quick brown fox jumps over the lazy dog.",
+ "69d7d3b0afba81826d27024c17f7f183659ed0812cf27b382eaef9fdc29b5712");
+
+ ROW("blake2b_384_pangram",
+ QCryptographicHash::Blake2b_384,
+ "The quick brown fox jumps over the lazy dog",
+ "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d");
+
+ ROW("blake2b_384_pangram_dot",
+ QCryptographicHash::Blake2b_384,
+ "The quick brown fox jumps over the lazy dog.",
+ "16d65de1a3caf1c26247234c39af636284c7e19ca448c0de788272081410778852c94d9cef6b939968d4f872c7f78337");
+
+ ROW("blake2b_512_pangram",
+ QCryptographicHash::Blake2b_512,
+ "The quick brown fox jumps over the lazy dog",
+ "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918");
+
+ ROW("blake2b_512_pangram_dot",
+ QCryptographicHash::Blake2b_512,
+ "The quick brown fox jumps over the lazy dog.",
+ "87af9dc4afe5651b7aa89124b905fd214bf17c79af58610db86a0fb1e0194622a4e9d8e395b352223a8183b0d421c0994b98286cbf8c68a495902e0fe6e2bda2");
+
+ // BLAKE2s
+ ROW("blake2s_128_pangram",
+ QCryptographicHash::Blake2s_128,
+ "The quick brown fox jumps over the lazy dog",
+ "96fd07258925748a0d2fb1c8a1167a73");
+
+ ROW("blake2s_128_pangram_dot",
+ QCryptographicHash::Blake2s_128,
+ "The quick brown fox jumps over the lazy dog.",
+ "1f298f2e1f9c2490e506c2308f64e7c0");
+
+ ROW("blake2s_160_pangram",
+ QCryptographicHash::Blake2s_160,
+ "The quick brown fox jumps over the lazy dog",
+ "5a604fec9713c369e84b0ed68daed7d7504ef240");
+
+ ROW("blake2s_160_pangram_dot",
+ QCryptographicHash::Blake2s_160,
+ "The quick brown fox jumps over the lazy dog.",
+ "cd4a863226463aac852662d16275d399966e3ffe");
+
+ ROW("blake2s_224_pangram",
+ QCryptographicHash::Blake2s_224,
+ "The quick brown fox jumps over the lazy dog",
+ "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912");
+
+ ROW("blake2s_224_pangram_dot",
+ QCryptographicHash::Blake2s_224,
+ "The quick brown fox jumps over the lazy dog.",
+ "fd1557500ef49f308882969507acd18a13e155c26f8fcd82f9bf2ff7");
+
+ ROW("blake2s_256_pangram",
+ QCryptographicHash::Blake2s_256,
+ "The quick brown fox jumps over the lazy dog",
+ "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812");
+
+ ROW("blake2s_256_pangram_dot",
+ QCryptographicHash::Blake2s_256,
+ "The quick brown fox jumps over the lazy dog.",
+ "95bca6e1b761dca1323505cc629949a0e03edf11633cc7935bd8b56f393afcf2");
+
+#undef ROW
+}
+
+void tst_QCryptographicHash::blake2()
+{
+ QFETCH(QCryptographicHash::Algorithm, algorithm);
+ QFETCH(QByteArray, data);
+ QFETCH(QByteArray, expectedResult);
+
+ const auto result = QCryptographicHash::hash(data, algorithm);
+ QCOMPARE(result, expectedResult);
+}
+
void tst_QCryptographicHash::files_data() {
QTest::addColumn<QString>("filename");
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
@@ -293,14 +474,192 @@ void tst_QCryptographicHash::files()
}
}
-void tst_QCryptographicHash::hashLength()
+void tst_QCryptographicHash::hashLength_data()
{
+ QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
auto metaEnum = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
for (int i = 0, value = metaEnum.value(i); value != -1; value = metaEnum.value(++i)) {
auto algorithm = QCryptographicHash::Algorithm(value);
- QByteArray output = QCryptographicHash::hash(QByteArrayLiteral("test"), algorithm);
- QCOMPARE(QCryptographicHash::hashLength(algorithm), output.length());
+ QTest::addRow("%s", metaEnum.key(i)) << algorithm;
+ }
+}
+
+void tst_QCryptographicHash::hashLength()
+{
+ QFETCH(const QCryptographicHash::Algorithm, algorithm);
+
+ qsizetype expectedSize;
+ if (algorithm == QCryptographicHash::NumAlgorithms) {
+ // It's UB to call ::hash() with NumAlgorithms, but hashLength() is
+ // fine and returns 0 for invalid values:
+ expectedSize = 0;
+ } else {
+ expectedSize = QCryptographicHash::hash("test", algorithm).size();
+ }
+ QCOMPARE(QCryptographicHash::hashLength(algorithm), expectedSize);
+}
+
+void tst_QCryptographicHash::addDataAcceptsNullByteArrayView()
+{
+ QFETCH(const QCryptographicHash::Algorithm, algorithm);
+
+ if (!QCryptographicHash::supportsAlgorithm(algorithm))
+ QSKIP("QCryptographicHash doesn't support this algorithm");
+
+ QCryptographicHash hash1(algorithm);
+ hash1.addData("meep");
+ hash1.addData(QByteArrayView{}); // after other data
+
+ QCryptographicHash hash2(algorithm);
+ hash2.addData(QByteArrayView{}); // before any other data
+ hash2.addData("meep");
+
+ const auto expected = QCryptographicHash::hash("meep", algorithm);
+
+ QCOMPARE(hash1.resultView(), expected);
+ QCOMPARE(hash2.resultView(), expected);
+}
+
+void tst_QCryptographicHash::move()
+{
+ QCryptographicHash hash1(QCryptographicHash::Sha1);
+ hash1.addData("a");
+
+ // move constructor
+ auto hash2(std::move(hash1));
+ hash2.addData("b");
+
+ // move assign operator
+ QCryptographicHash hash3(QCryptographicHash::Sha256);
+ hash3.addData("no effect on the end result");
+ hash3 = std::move(hash2);
+ hash3.addData("c");
+
+ QCOMPARE(hash3.resultView(), QByteArray::fromHex("A9993E364706816ABA3E25717850C26C9CD0D89D"));
+}
+
+void tst_QCryptographicHash::swap()
+{
+ QCryptographicHash hash1(QCryptographicHash::Sha1);
+ QCryptographicHash hash2(QCryptographicHash::Sha256);
+
+ hash1.addData("da");
+ hash2.addData("te");
+
+ hash1.swap(hash2);
+
+ hash2.addData("ta");
+ hash1.addData("st");
+
+ QCOMPARE(hash2.result(), QCryptographicHash::hash("data", QCryptographicHash::Sha1));
+ QCOMPARE(hash1.result(), QCryptographicHash::hash("test", QCryptographicHash::Sha256));
+}
+
+void tst_QCryptographicHash::ensureLargeData()
+{
+#if QT_POINTER_SIZE > 4
+ QElapsedTimer timer;
+ timer.start();
+ const size_t GiB = 1024 * 1024 * 1024;
+ if (large.size() == 4 * GiB + 1)
+ return;
+ try {
+ large.resize(4 * GiB + 1, '\0');
+ } catch (const std::bad_alloc &) {
+ QSKIP("Could not allocate 4GiB plus one byte of RAM.");
+ }
+ QCOMPARE(large.size(), 4 * GiB + 1);
+ large.back() = '\1';
+ qDebug("created dataset in %lld ms", timer.elapsed());
+#endif
+}
+
+void tst_QCryptographicHash::moreThan4GiBOfData_data()
+{
+#if QT_POINTER_SIZE > 4
+ if (ensureLargeData(); large.empty())
+ return;
+ QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
+ auto me = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
+ auto row = [me] (QCryptographicHash::Algorithm algo) {
+ QTest::addRow("%s", me.valueToKey(int(algo))) << algo;
+ };
+ // these are reasonably fast (O(secs))
+ row(QCryptographicHash::Md4);
+ row(QCryptographicHash::Md5);
+ row(QCryptographicHash::Sha1);
+ if (!qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) {
+ // This is important but so slow (O(minute)) that, on CI, it tends to time out.
+ // Retain it for manual runs, all the same, as most dev machines will be fast enough.
+ row(QCryptographicHash::Sha512);
+ }
+ // the rest is just too slow
+#else
+ QSKIP("This test is 64-bit only.");
+#endif
+}
+
+void tst_QCryptographicHash::moreThan4GiBOfData()
+{
+ QFETCH(const QCryptographicHash::Algorithm, algorithm);
+
+ using MaybeThread = std::thread;
+
+ QElapsedTimer timer;
+ timer.start();
+ const auto sg = qScopeGuard([&] {
+ qDebug() << algorithm << "test finished in" << timer.restart() << "ms";
+ });
+
+ const auto view = QByteArrayView{large};
+ const auto first = view.first(view.size() / 2);
+ const auto last = view.sliced(view.size() / 2);
+
+ QByteArray single;
+ QByteArray chunked;
+
+ auto t = MaybeThread{[&] {
+ QCryptographicHash h(algorithm);
+ h.addData(view);
+ single = h.result();
+ }};
+ {
+ QCryptographicHash h(algorithm);
+ h.addData(first);
+ h.addData(last);
+ chunked = h.result();
}
+ t.join();
+
+ QCOMPARE(single, chunked);
+}
+
+void tst_QCryptographicHash::keccakBufferOverflow()
+{
+#if QT_POINTER_SIZE == 4
+ QSKIP("This is a 64-bit-only test");
+#else
+
+ if (ensureLargeData(); large.empty())
+ return;
+
+ QElapsedTimer timer;
+ timer.start();
+ const auto sg = qScopeGuard([&] {
+ qDebug() << "test finished in" << timer.restart() << "ms";
+ });
+
+ constexpr qsizetype magic = INT_MAX/4;
+ QCOMPARE_GE(large.size(), size_t(magic + 1));
+
+ QCryptographicHash hash(QCryptographicHash::Algorithm::Keccak_224);
+ const auto first = QByteArrayView{large}.first(1);
+ const auto second = QByteArrayView{large}.sliced(1, magic);
+ hash.addData(first);
+ hash.addData(second);
+ (void)hash.resultView();
+ QVERIFY(true); // didn't crash
+#endif
}
QTEST_MAIN(tst_QCryptographicHash)
diff --git a/tests/auto/corelib/tools/qduplicatetracker/CMakeLists.txt b/tests/auto/corelib/tools/qduplicatetracker/CMakeLists.txt
new file mode 100644
index 0000000000..13645c50b8
--- /dev/null
+++ b/tests/auto/corelib/tools/qduplicatetracker/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qduplicatetracker Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qduplicatetracker LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qduplicatetracker
+ SOURCES
+ tst_qduplicatetracker.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp b/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp
new file mode 100644
index 0000000000..ad0b6abbc7
--- /dev/null
+++ b/tests/auto/corelib/tools/qduplicatetracker/tst_qduplicatetracker.cpp
@@ -0,0 +1,230 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+
+#include <QtCore/private/qduplicatetracker_p.h>
+
+#include <QObject>
+
+#include <string>
+#include <utility>
+
+class tst_QDuplicateTracker : public QObject
+{
+ Q_OBJECT
+private slots:
+ void hasSeen();
+ void clear();
+ void appendTo();
+ void appendTo_special();
+};
+
+void tst_QDuplicateTracker::hasSeen()
+{
+ {
+ QDuplicateTracker<int, 2> tracker;
+ QVERIFY(!tracker.hasSeen(0));
+ QVERIFY(tracker.hasSeen(0));
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(tracker.hasSeen(1));
+ // past the prealloc amount
+ QVERIFY(!tracker.hasSeen(2));
+ QVERIFY(tracker.hasSeen(2));
+ }
+
+ {
+ QDuplicateTracker<QString, 2> tracker;
+ QString string1("string1");
+ QString string2("string2");
+ QString string2_2("string2");
+ QString string3("string3");
+
+ // Move when seen
+ QVERIFY(!tracker.hasSeen(string1));
+ QVERIFY(tracker.hasSeen(std::move(string1)));
+
+ // Move when unseen
+ QVERIFY(!tracker.hasSeen(std::move(string2)));
+ QVERIFY(tracker.hasSeen(string2_2));
+
+ // Past the prealloc amount
+ QVERIFY(!tracker.hasSeen(string3));
+ QVERIFY(tracker.hasSeen(string3));
+ }
+
+ {
+ QDuplicateTracker<std::string, 2> tracker;
+ std::string string1("string1");
+ std::string string2("string2");
+ std::string string2_2("string2");
+ std::string string3("string3");
+
+ // Move when seen
+ QVERIFY(!tracker.hasSeen(string1));
+ QVERIFY(tracker.hasSeen(std::move(string1)));
+
+ // Move when unseen
+ QVERIFY(!tracker.hasSeen(std::move(string2)));
+ QVERIFY(tracker.hasSeen(string2_2));
+
+ // Past the prealloc amount
+ QVERIFY(!tracker.hasSeen(string3));
+ QVERIFY(tracker.hasSeen(string3));
+ }
+
+}
+
+void tst_QDuplicateTracker::clear()
+{
+ QDuplicateTracker<int, 2> tracker;
+ QVERIFY(!tracker.hasSeen(0));
+ QVERIFY(tracker.hasSeen(0));
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(tracker.hasSeen(1));
+
+ tracker.clear();
+ QVERIFY(!tracker.hasSeen(0));
+ QVERIFY(tracker.hasSeen(0));
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(tracker.hasSeen(1));
+}
+
+void tst_QDuplicateTracker::appendTo()
+{
+ QDuplicateTracker<int, 2> tracker;
+ QVERIFY(!tracker.hasSeen(0));
+ QVERIFY(!tracker.hasSeen(1));
+ QList<int> a;
+ a.append(-1);
+ tracker.appendTo(a);
+ std::sort(a.begin(), a.end());
+ QCOMPARE(a, QList<int>({ -1, 0, 1 }));
+
+ QList<int> b;
+ tracker.appendTo(b);
+ std::sort(b.begin(), b.end());
+ QCOMPARE(b, QList<int>({ 0, 1 }));
+
+ QVERIFY(!tracker.hasSeen(2));
+ QList<int> c;
+ std::move(tracker).appendTo(c);
+ std::sort(c.begin(), c.end());
+ QCOMPARE(c, QList<int>({ 0, 1, 2 }));
+ if (QDuplicateTracker<int, 2>::uses_pmr) {
+ // the following is only true if we use the std container
+ QVERIFY(!tracker.hasSeen(0));
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(!tracker.hasSeen(2));
+ }
+}
+
+struct ConstructionCounted
+{
+ ConstructionCounted(int i) : i(i) { }
+ ConstructionCounted(ConstructionCounted &&other) noexcept
+ : i(other.i), copies(other.copies), moves(other.moves + 1)
+ {
+ // set to some easily noticeable values
+ other.i = -64;
+ other.copies = -64;
+ other.moves = -64;
+ }
+ ConstructionCounted &operator=(ConstructionCounted &&other) noexcept
+ {
+ ConstructionCounted moved = std::move(other);
+ swap(moved);
+ // set to some easily noticeable values
+ other.i = -64;
+ other.copies = -64;
+ other.moves = -64;
+ return *this;
+ }
+ ConstructionCounted(const ConstructionCounted &other) noexcept
+ : i(other.i), copies(other.copies + 1), moves(other.moves)
+ {
+ }
+ ConstructionCounted &operator=(const ConstructionCounted &other) noexcept
+ {
+ ConstructionCounted copy = other;
+ swap(copy);
+ return *this;
+ }
+ ~ConstructionCounted() = default;
+
+ friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs)
+ {
+ return lhs.i == rhs.i;
+ }
+
+ QString toString() { return QString::number(i); }
+
+ void swap(ConstructionCounted &other)
+ {
+ std::swap(copies, other.copies);
+ std::swap(i, other.i);
+ std::swap(moves, other.moves);
+ }
+
+ int i;
+ int copies = 0;
+ int moves = 0;
+};
+
+// for std::unordered_set
+namespace std {
+template<>
+struct hash<ConstructionCounted>
+{
+ std::size_t operator()(const ConstructionCounted &c) const noexcept { return c.i; }
+};
+}
+
+// for QSet
+size_t qHash(const ConstructionCounted &c, std::size_t seed = 0)
+{
+ return qHash(c.i, seed);
+}
+
+void tst_QDuplicateTracker::appendTo_special()
+{
+ QDuplicateTracker<ConstructionCounted> tracker(3);
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(!tracker.hasSeen(2));
+ QVERIFY(!tracker.hasSeen(3));
+
+ QVERIFY(tracker.hasSeen(1));
+ QVERIFY(tracker.hasSeen(2));
+ QVERIFY(tracker.hasSeen(3));
+ {
+ QList<ConstructionCounted> a;
+ a.reserve(3);
+ tracker.appendTo(a);
+ for (const auto &counter : a) {
+ QCOMPARE(counter.moves, 1);
+ QCOMPARE(counter.copies, 1);
+ }
+ }
+ QVERIFY(tracker.hasSeen(1));
+ QVERIFY(tracker.hasSeen(2));
+ QVERIFY(tracker.hasSeen(3));
+ {
+ QList<ConstructionCounted> a;
+ a.reserve(3);
+ std::move(tracker).appendTo(a);
+ if (QDuplicateTracker<ConstructionCounted>::uses_pmr) {
+ // the following is only true if we use the std container
+ for (const auto &counter : a) {
+ QCOMPARE(counter.moves, 2);
+ QCOMPARE(counter.copies, 0);
+ }
+ QVERIFY(!tracker.hasSeen(1));
+ QVERIFY(!tracker.hasSeen(2));
+ QVERIFY(!tracker.hasSeen(3));
+ }
+ }
+}
+
+QTEST_MAIN(tst_QDuplicateTracker)
+
+#include "tst_qduplicatetracker.moc"
diff --git a/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt b/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt
new file mode 100644
index 0000000000..3f76f8a38f
--- /dev/null
+++ b/tests/auto/corelib/tools/qeasingcurve/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qeasingcurve Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qeasingcurve LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qeasingcurve
+ SOURCES
+ tst_qeasingcurve.cpp
+)
diff --git a/tests/auto/corelib/tools/qeasingcurve/qeasingcurve.pro b/tests/auto/corelib/tools/qeasingcurve/qeasingcurve.pro
deleted file mode 100644
index 80c5a94a83..0000000000
--- a/tests/auto/corelib/tools/qeasingcurve/qeasingcurve.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qeasingcurve
-QT = core testlib
-SOURCES = tst_qeasingcurve.cpp
diff --git a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
index 2a9c1e1e41..fc8c1a3e5c 100644
--- a/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
+++ b/tests/auto/corelib/tools/qeasingcurve/tst_qeasingcurve.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <qeasingcurve.h>
@@ -399,7 +374,7 @@ void tst_QEasingCurve::valueForProgress()
// in theory the baseline should't have an error of more than 0.00005 due to how its rounded,
// but due to FP imprecision, we have to adjust the error a bit more.
const qreal errorBound = 0.00006;
- for (int i = 0; i < at.count(); ++i) {
+ for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal error = qAbs(ex - curve.valueForProgress(at.at(i)/qreal(100)));
QVERIFY(error <= errorBound);
@@ -428,9 +403,9 @@ void tst_QEasingCurve::setCustomType()
QCOMPARE(curve.valueForProgress(0.15), 0.1);
QCOMPARE(curve.valueForProgress(0.20), 0.2);
QCOMPARE(curve.valueForProgress(0.25), 0.2);
- // QTBUG-69947, MinGW 7.3 returns 0.2
+ // QTBUG-69947, MinGW 7.3, 8.1 x86 returns 0.2
#if defined(Q_CC_MINGW)
-#if !defined(__GNUC__) || __GNUC__ != 7 || __GNUC_MINOR__ < 3
+#if !defined(__GNUC__) || defined(__MINGW64__)
QCOMPARE(curve.valueForProgress(0.30), 0.3);
#endif
#endif
@@ -501,7 +476,7 @@ class tst_QEasingProperties : public QObject
Q_OBJECT
Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing)
public:
- tst_QEasingProperties(QObject *parent = 0) : QObject(parent) {}
+ tst_QEasingProperties(QObject *parent = nullptr) : QObject(parent) {}
QEasingCurve easing() const { return e; }
void setEasing(const QEasingCurve& value) { e = value; }
@@ -546,10 +521,9 @@ void tst_QEasingCurve::properties()
void tst_QEasingCurve::metaTypes()
{
- QVERIFY(QMetaType::type("QEasingCurve") == QMetaType::QEasingCurve);
+ QVERIFY(QMetaType::fromName("QEasingCurve").id() == QMetaType::QEasingCurve);
- QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QEasingCurve)),
- QByteArray("QEasingCurve"));
+ QCOMPARE(QByteArray(QMetaType(QMetaType::QEasingCurve).name()), QByteArray("QEasingCurve"));
QVERIFY(QMetaType::isRegistered(QMetaType::QEasingCurve));
@@ -600,18 +574,18 @@ void tst_QEasingCurve::bezierSpline_data()
static inline void setupBezierSpline(QEasingCurve *easingCurve, const QString &string)
{
- QStringList pointStr = string.split(QLatin1Char(' '));
+ const QStringList pointStr = string.split(QLatin1Char(' '));
- QVector<QPointF> points;
- foreach (const QString &str, pointStr) {
+ QList<QPointF> points;
+ for (const QString &str : pointStr) {
QStringList coordStr = str.split(QLatin1Char(','));
QPointF point(coordStr.first().toDouble(), coordStr.last().toDouble());
points.append(point);
}
- QVERIFY(points.count() % 3 == 0);
+ QVERIFY(points.size() % 3 == 0);
- for (int i = 0; i < points.count() / 3; i++) {
+ for (int i = 0; i < points.size() / 3; i++) {
QPointF c1 = points.at(i * 3);
QPointF c2 = points.at(i * 3 + 1);
QPointF p1 = points.at(i * 3 + 2);
@@ -629,7 +603,7 @@ void tst_QEasingCurve::bezierSpline()
setupBezierSpline(&bezierEasingCurve, definition);
const qreal errorBound = 0.002;
- for (int i = 0; i < at.count(); ++i) {
+ for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal value = bezierEasingCurve.valueForProgress(at.at(i)/qreal(100));
const qreal error = qAbs(ex - value);
@@ -668,11 +642,11 @@ void tst_QEasingCurve::tcbSpline_data()
static inline void setupTCBSpline(QEasingCurve *easingCurve, const QString &string)
{
- QStringList pointStr = string.split(QLatin1Char(' '));
+ const QStringList pointStr = string.split(QLatin1Char(' '));
- foreach (const QString &str, pointStr) {
+ for (const QString &str : pointStr) {
QStringList coordStr = str.split(QLatin1Char(','));
- Q_ASSERT(coordStr.count() == 5);
+ Q_ASSERT(coordStr.size() == 5);
QPointF point(coordStr.first().toDouble(), coordStr.at(1).toDouble());
qreal t = coordStr.at(2).toDouble();
qreal c = coordStr.at(3).toDouble();
@@ -691,7 +665,7 @@ void tst_QEasingCurve::tcbSpline()
setupTCBSpline(&tcbEasingCurve, definition);
const qreal errorBound = 0.002;
- for (int i = 0; i < at.count(); ++i) {
+ for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal value = tcbEasingCurve.valueForProgress(at.at(i)/qreal(100));
const qreal error = qAbs(ex - value);
diff --git a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt
new file mode 100644
index 0000000000..280918e302
--- /dev/null
+++ b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qexplicitlyshareddatapointer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qexplicitlyshareddatapointer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qexplicitlyshareddatapointer
+ SOURCES
+ tst_qexplicitlyshareddatapointer.cpp
+)
diff --git a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/qexplicitlyshareddatapointer.pro b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/qexplicitlyshareddatapointer.pro
deleted file mode 100644
index 45fe1f60fe..0000000000
--- a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/qexplicitlyshareddatapointer.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qexplicitlyshareddatapointer
-QT = core testlib
-SOURCES = tst_qexplicitlyshareddatapointer.cpp
diff --git a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp
index e89e634841..5e105a090a 100644
--- a/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp
+++ b/tests/auto/corelib/tools/qexplicitlyshareddatapointer/tst_qexplicitlyshareddatapointer.cpp
@@ -1,33 +1,8 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+
+#include <QTest>
#include <QtCore/QSharedData>
/*!
@@ -79,8 +54,8 @@ public:
class Derived : public Base
{
public:
- virtual Base *clone() { return new Derived(*this); }
- virtual bool isBase() const { return false; }
+ virtual Base *clone() override { return new Derived(*this); }
+ virtual bool isBase() const override { return false; }
};
QT_BEGIN_NAMESPACE
@@ -169,7 +144,7 @@ void tst_QExplicitlySharedDataPointer::data() const
pointer.data();
/* Check that this cast is possible. */
- static_cast<const MyClass *>(pointer.data());
+ Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
QVERIFY(! (pointer == nullptr));
QVERIFY(! (nullptr == pointer));
@@ -181,7 +156,7 @@ void tst_QExplicitlySharedDataPointer::data() const
pointer.data();
/* Check that this cast is possible. */
- static_cast<const MyClass *>(pointer.data());
+ Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
/* Must not mutate the pointer. */
@@ -190,8 +165,8 @@ void tst_QExplicitlySharedDataPointer::data() const
pointer.data();
/* Check that these casts are possible. */
- static_cast<MyClass *>(pointer.data());
- static_cast<const MyClass *>(pointer.data());
+ Q_UNUSED(static_cast<MyClass *>(pointer.data()));
+ Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
/* Must not mutate the pointer. */
@@ -200,8 +175,8 @@ void tst_QExplicitlySharedDataPointer::data() const
pointer.data();
/* Check that these casts are possible. */
- static_cast<MyClass *>(pointer.data());
- static_cast<const MyClass *>(pointer.data());
+ Q_UNUSED(static_cast<MyClass *>(pointer.data()));
+ Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
}
@@ -248,4 +223,3 @@ void tst_QExplicitlySharedDataPointer::swap() const
QTEST_MAIN(tst_QExplicitlySharedDataPointer)
#include "tst_qexplicitlyshareddatapointer.moc"
-// vim: et:ts=4:sw=4:sts=4
diff --git a/tests/auto/corelib/tools/qflatmap/CMakeLists.txt b/tests/auto/corelib/tools/qflatmap/CMakeLists.txt
new file mode 100644
index 0000000000..bc98c669fc
--- /dev/null
+++ b/tests/auto/corelib/tools/qflatmap/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qflatmap Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qflatmap LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qflatmap
+ SOURCES
+ tst_qflatmap.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp b/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp
new file mode 100644
index 0000000000..986cf2407b
--- /dev/null
+++ b/tests/auto/corelib/tools/qflatmap/tst_qflatmap.cpp
@@ -0,0 +1,732 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#define QT_USE_QSTRINGBUILDER
+#define QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
+
+#include <QTest>
+
+#include <private/qflatmap_p.h>
+#include <qbytearray.h>
+#include <qstring.h>
+#include <qstringview.h>
+#include <qvarlengtharray.h>
+
+#include <algorithm>
+#include <list>
+#include <tuple>
+
+static constexpr bool is_even(int n) { return n % 2 == 0; }
+static constexpr bool is_empty(QAnyStringView v) { return v.isEmpty(); }
+
+namespace {
+template <typename P>
+constexpr inline bool is_pair_impl_v = false;
+template <typename T, typename S>
+constexpr inline bool is_pair_impl_v<std::pair<T,S>> = true;
+template <typename P>
+constexpr inline bool is_pair_v = is_pair_impl_v<std::decay_t<P>>;
+template <typename P>
+using if_pair = std::enable_if_t<is_pair_v<P>, bool>;
+}
+
+class tst_QFlatMap : public QObject
+{
+ Q_OBJECT
+private slots:
+ void constructing();
+ void constAccess();
+ void insertion();
+ void insertRValuesAndLValues();
+ void removal();
+ void extraction();
+ void iterators();
+ void remove_if_pair() { remove_if_impl([](const auto &p) -> if_pair<decltype(p)> { return is_even(p.first) && is_empty(p.second); }); }
+ void remove_if_key_value() { remove_if_impl([](const auto &k, const auto &v) { return is_even(k) && is_empty(v); }); }
+ void remove_if_key() { remove_if_impl([](int k) { return is_even(k); }, true); }
+ void statefulComparator();
+ void transparency_using();
+ void transparency_struct();
+ void try_emplace_and_insert_or_assign();
+ void viewIterators();
+ void varLengthArray();
+
+private:
+ template <typename Compare>
+ void transparency_impl();
+ template <typename Predicate>
+ void remove_if_impl(Predicate p, bool removeNonEmptyValues = false);
+};
+
+void tst_QFlatMap::constructing()
+{
+ using Map = QFlatMap<int, QByteArray>;
+ Map fmDefault;
+ QVERIFY(fmDefault.isEmpty());
+ QCOMPARE(fmDefault.size(), Map::size_type(0));
+ QCOMPARE(fmDefault.size(), fmDefault.count());
+
+ auto key_compare = fmDefault.key_comp();
+ auto selfbuilt_value_compare
+ = [&key_compare](const Map::value_type &a, const Map::value_type &b)
+ {
+ return key_compare(a.first, b.first);
+ };
+ auto value_compare = fmDefault.value_comp();
+
+ Map::key_container_type kv = { 6, 2, 1 };
+ Map::mapped_container_type mv = { "foo", "bar", "baz" };
+ Map fmCopy{kv, mv};
+ QCOMPARE(fmCopy.size(), Map::size_type(3));
+ QVERIFY(std::is_sorted(fmCopy.begin(), fmCopy.end(), selfbuilt_value_compare));
+ QVERIFY(std::is_sorted(fmCopy.begin(), fmCopy.end(), value_compare));
+
+ Map fmMove{
+ Map::key_container_type{ 6, 2, 1 },
+ Map::mapped_container_type{ "foo", "bar", "baz" }
+ };
+ QCOMPARE(fmMove.size(), Map::size_type(3));
+ QVERIFY(std::is_sorted(fmMove.begin(), fmMove.end(), value_compare));
+
+ auto fmInitList = Map{ { 1, 2 }, { "foo", "bar" } };
+ QVERIFY(std::is_sorted(fmInitList.begin(), fmInitList.end(), value_compare));
+
+ auto fmRange = Map(fmCopy.begin(), fmCopy.end());
+ QVERIFY(std::is_sorted(fmRange.begin(), fmRange.end(), value_compare));
+
+ kv.clear();
+ mv.clear();
+ std::vector<Map::value_type> sv;
+ for (auto it = fmRange.begin(); it != fmRange.end(); ++it) {
+ kv.push_back(it->first);
+ mv.push_back(it->second);
+ sv.push_back(*it);
+ }
+ auto fmFromSortedVectorCopy = Map(Qt::OrderedUniqueRange, kv, mv);
+ auto fmFromSortedVectorMove = Map(Qt::OrderedUniqueRange, Map::key_container_type(kv),
+ Map::mapped_container_type(mv));
+ auto fmFromSortedInitList = Map(Qt::OrderedUniqueRange, { { 1, "foo" }, { 2, "bar" } });
+ auto fmFromSortedRange = Map(Qt::OrderedUniqueRange, sv.begin(), sv.end());
+}
+
+void tst_QFlatMap::constAccess()
+{
+ using Map = QFlatMap<QByteArray, QByteArray>;
+ const Map m{ { { "foo", "FOO" }, { "bar", "BAR" } } };
+
+ const std::vector<Map::value_type> v{ { "foo", "FOO" }, { "bar", "BAR" } };
+
+ QCOMPARE(m.value("foo").data(), "FOO");
+ QCOMPARE(m.value("bar").data(), "BAR");
+ QCOMPARE(m.value("nix"), QByteArray());
+ QCOMPARE(m.value("nix", "NIX").data(), "NIX");
+ QCOMPARE(m["foo"].data(), "FOO");
+ QCOMPARE(m["bar"].data(), "BAR");
+ QCOMPARE(m["nix"], QByteArray());
+ QVERIFY(m.contains("foo"));
+ QVERIFY(!m.contains("nix"));
+}
+
+void tst_QFlatMap::insertion()
+{
+ using Map = QFlatMap<QByteArray, QByteArray>;
+ Map m;
+ QByteArray foo = "foo";
+ m[foo] = foo.toUpper();
+ m["bar"] = "BAR";
+ m["baz"] = "BAZ";
+ QVERIFY(m.insert("oof", "eek").second);
+ QVERIFY(!m.insert("oof", "OOF").second);
+ const std::vector<Map::value_type> container = { { "bla", "BLA" }, { "blubb", "BLUBB" } };
+ m.insert(container.begin(), container.end());
+ QCOMPARE(m.value("foo").data(), "FOO");
+ QCOMPARE(m.value("bar").data(), "BAR");
+ QCOMPARE(m.value("baz").data(), "BAZ");
+ QCOMPARE(m.value("oof").data(), "eek");
+ QCOMPARE(m.value("bla").data(), "BLA");
+ QCOMPARE(m.value("blubb").data(), "BLUBB");
+
+ Map::value_type a1[] = { { "narf", "NARF" },
+ { "zort", "ZORT" },
+ { "troz", "TROZ" } };
+ Map::value_type a2[] = { { "gnampf", "GNAMPF" },
+ { "narf", "NARFFFF" },
+ { "narf", "NARFFFFF" },
+ { "narf", "NARFFFFFF" } };
+ m.insert(std::begin(a1), std::end(a1));
+ m.insert(Qt::OrderedUniqueRange, std::begin(a2), std::end(a2));
+ QCOMPARE(m.size(), 10);
+ QCOMPARE(m.value("narf").data(), "NARF");
+ QCOMPARE(m.value("gnampf").data(), "GNAMPF");
+}
+
+void tst_QFlatMap::insertRValuesAndLValues()
+{
+ using Map = QFlatMap<QByteArray, QByteArray>;
+ const QByteArray foo = QByteArrayLiteral("foo");
+ const QByteArray bar = QByteArrayLiteral("bar");
+
+ auto rvalue = [](const QByteArray &ba) { return ba; };
+#define lvalue(x) x
+
+ {
+ Map m;
+ QVERIFY( m.insert(lvalue(foo), lvalue(bar)).second);
+ QVERIFY(!m.insert(lvalue(foo), lvalue(bar)).second);
+ }
+
+ {
+ Map m;
+ QVERIFY( m.insert(lvalue(foo), rvalue(bar)).second);
+ QVERIFY(!m.insert(lvalue(foo), rvalue(bar)).second);
+ }
+
+ {
+ Map m;
+ QVERIFY( m.insert(rvalue(foo), lvalue(bar)).second);
+ QVERIFY(!m.insert(rvalue(foo), lvalue(bar)).second);
+ }
+
+ {
+ Map m;
+ QVERIFY( m.insert(rvalue(foo), rvalue(bar)).second);
+ QVERIFY(!m.insert(rvalue(foo), rvalue(bar)).second);
+ }
+
+#undef lvalue
+}
+
+void tst_QFlatMap::extraction()
+{
+ using Map = QFlatMap<int, QByteArray>;
+ Map::key_container_type expectedKeys = { 1, 2, 3 };
+ Map::mapped_container_type expectedValues = { "een", "twee", "dree" };
+ Map m(Qt::OrderedUniqueRange, expectedKeys, expectedValues);
+ auto keys = m.keys();
+ auto values = m.values();
+ QCOMPARE(keys, expectedKeys);
+ QCOMPARE(values, expectedValues);
+ Map::containers c = std::move(m).extract();
+ QCOMPARE(c.keys, expectedKeys);
+ QCOMPARE(c.values, expectedValues);
+}
+
+void tst_QFlatMap::iterators()
+{
+ using Map = QFlatMap<int, QByteArray>;
+ auto m = Map{ Qt::OrderedUniqueRange, { { 1, "foo" }, { 2, "bar" }, { 3, "baz" } } };
+ {
+ // forward / backward
+ Map::iterator a = m.begin();
+ QVERIFY(a != m.end());
+ QCOMPARE(a.key(), 1);
+ QCOMPARE(a.value(), "foo");
+ ++a;
+ QCOMPARE(a.key(), 2);
+ QCOMPARE(a.value(), "bar");
+ Map::iterator b = a++;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(2, "bar"));
+ QCOMPARE(++a, m.end());
+ --a;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ a.value() = "buzz";
+ b = a--;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+ QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "buzz"));
+ b.value() = "baz";
+
+ // random access
+ a = m.begin();
+ a += 2;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ a = m.begin() + 1;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+ a = 1 + m.begin();
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+ a = m.end() - 1;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ b = m.end();
+ b -= 1;
+ QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "baz"));
+ QCOMPARE(m.end() - m.begin(), m.size());
+
+ // comparison
+ a = m.begin() + m.size() - 1;
+ b = m.end() - 1;
+ QVERIFY(a == b);
+ a = m.begin();
+ b = m.end();
+ QVERIFY(a < b);
+ QVERIFY(a <= b);
+ QVERIFY(b > a);
+ QVERIFY(b >= a);
+ a = b;
+ QVERIFY(!(a < b));
+ QVERIFY(a <= b);
+ QVERIFY(!(b > a));
+ QVERIFY(b >= a);
+
+ // de-referencing
+ a = m.begin();
+ auto ref0 = *a;
+ QCOMPARE(ref0.first, 1);
+ QCOMPARE(ref0.second, "foo");
+ auto ref1 = a[1];
+ QCOMPARE(ref1.first, 2);
+ QCOMPARE(ref1.second, "bar");
+ }
+ {
+ // forward / backward
+ Map::const_iterator a = m.cbegin();
+ QVERIFY(a != m.cend());
+ QCOMPARE(a.key(), 1);
+ QCOMPARE(a.value(), "foo");
+ ++a;
+ QCOMPARE(a.key(), 2);
+ QCOMPARE(a.value(), "bar");
+ Map::const_iterator b = a++;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(2, "bar"));
+ QCOMPARE(++a, m.cend());
+ --a;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ b = a--;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+
+ // random access
+ a = m.cbegin();
+ a += 2;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ a = m.cbegin() + 1;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+ a = 1 + m.cbegin();
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
+ a = m.cend() - 1;
+ QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
+ b = m.cend();
+ b -= 1;
+ QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "baz"));
+ QCOMPARE(m.cend() - m.cbegin(), m.size());
+
+ // comparison
+ a = m.cbegin() + m.size() - 1;
+ b = m.cend() - 1;
+ QVERIFY(a == b);
+ a = m.cbegin();
+ b = m.cend();
+ QVERIFY(a < b);
+ QVERIFY(a <= b);
+ QVERIFY(b > a);
+ QVERIFY(b >= a);
+ a = b;
+ QVERIFY(!(a < b));
+ QVERIFY(a <= b);
+ QVERIFY(!(b > a));
+ QVERIFY(b >= a);
+
+ // de-referencing
+ a = m.cbegin();
+ auto ref0 = *a;
+ QCOMPARE(ref0.first, 1);
+ QCOMPARE(ref0.second, "foo");
+ auto ref1 = a[1];
+ QCOMPARE(ref1.first, 2);
+ QCOMPARE(ref1.second, "bar");
+ }
+ {
+ Map::iterator it = m.begin();
+ Map::const_iterator cit = it;
+ Q_UNUSED(it);
+ Q_UNUSED(cit);
+ }
+ {
+ std::list<Map::value_type> revlst;
+ std::copy(m.begin(), m.end(), std::front_inserter(revlst));
+ std::vector<Map::value_type> v0;
+ std::copy(revlst.begin(), revlst.end(), std::back_inserter(v0));
+ std::vector<Map::value_type> v1;
+ std::copy(m.rbegin(), m.rend(), std::back_inserter(v1));
+ const Map cm = m;
+ std::vector<Map::value_type> v2;
+ std::copy(cm.rbegin(), cm.rend(), std::back_inserter(v2));
+ std::vector<Map::value_type> v3;
+ std::copy(m.crbegin(), m.crend(), std::back_inserter(v3));
+ QCOMPARE(v0, v1);
+ QCOMPARE(v1, v2);
+ QCOMPARE(v2, v3);
+ }
+}
+
+template <typename Pred>
+void tst_QFlatMap::remove_if_impl(Pred p, bool removeNonEmptyValues)
+{
+ // empty stays empty:
+ {
+ QFlatMap<int, QString> m;
+ QCOMPARE(m.remove_if(p), 0);
+ QVERIFY(m.isEmpty());
+ }
+ // a matching element is removed:
+ {
+ {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(0, "");
+ QCOMPARE(m.remove_if(p), 1);
+ QVERIFY(m.isEmpty());
+ }
+ if (removeNonEmptyValues) {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(0, "x");
+ QCOMPARE(m.remove_if(p), 1);
+ QVERIFY(m.isEmpty());
+ }
+ }
+ // a non-matching element is not removed:
+ {
+ {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(1, "");
+ QCOMPARE(m.remove_if(p), 0);
+ QVERIFY(m.contains(1));
+ QVERIFY(m[1].isEmpty());
+ }
+ if (removeNonEmptyValues) {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(1, "x");
+ QCOMPARE(m.remove_if(p), 0);
+ QVERIFY(m.contains(1));
+ QCOMPARE(m[1], "x");
+ }
+ }
+ // of matching and non-matching elements, only matching ones are removed:
+ {
+ {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(0, "");
+ m.insert_or_assign(1, "");
+ const auto copy = m;
+ QCOMPARE(m.remove_if(p), 1);
+ QCOMPARE(copy.size(), 2);
+ QCOMPARE(copy[0], "");
+ QCOMPARE(copy[1], "");
+ QCOMPARE(m.size(), 1);
+ QVERIFY(m.contains(1));
+ QVERIFY(m[1].isEmpty());
+ }
+ {
+ QFlatMap<int, QString> m;
+ m.insert_or_assign(1, "");
+ m.insert_or_assign(2, "");
+ QCOMPARE(m.remove_if(p), 1);
+ QCOMPARE(m.size(), 1);
+ QVERIFY(m.contains(1));
+ QVERIFY(m[1].isEmpty());
+ }
+ }
+}
+
+void tst_QFlatMap::removal()
+{
+ using Map = QFlatMap<int, QByteArray>;
+ Map m({ { 2, "bar" }, { 3, "baz" }, { 1, "foo" } });
+ QCOMPARE(m.value(2).data(), "bar");
+ QCOMPARE(m.take(2).data(), "bar");
+ QVERIFY(!m.contains(2));
+ QCOMPARE(m.size(), Map::size_type(2));
+ QVERIFY(m.remove(1));
+ QVERIFY(!m.contains(1));
+ QVERIFY(!m.remove(1));
+ QCOMPARE(m.size(), Map::size_type(1));
+ m.clear();
+ QVERIFY(m.isEmpty());
+ QVERIFY(m.empty());
+
+ m[1] = "een";
+ m[2] = "twee";
+ m[3] = "dree";
+ auto it = m.lower_bound(1);
+ QCOMPARE(it.key(), 1);
+ it = m.erase(it);
+ QCOMPARE(it.key(), 2);
+ QVERIFY(!m.contains(1));
+}
+
+void tst_QFlatMap::statefulComparator()
+{
+ struct CountingCompare {
+ mutable int count = 0;
+
+ bool operator()(const QString &lhs, const QString &rhs) const
+ {
+ ++count;
+ return lhs < rhs;
+ }
+ };
+
+ using Map = QFlatMap<QString, QString, CountingCompare>;
+ auto m1 = Map{ { "en", "een"}, { "to", "twee" }, { "tre", "dree" } };
+ QVERIFY(m1.key_comp().count > 0);
+ auto m2 = Map(m1.key_comp());
+ QCOMPARE(m2.key_comp().count, m1.key_comp().count);
+ m2.insert(m1.begin(), m1.end());
+ QVERIFY(m2.key_comp().count > m1.key_comp().count);
+}
+
+void tst_QFlatMap::transparency_using()
+{
+ struct StringViewCompare
+ {
+ using is_transparent [[maybe_unused]] = void;
+ bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
+ {
+ return lhs < rhs;
+ }
+ };
+ transparency_impl<StringViewCompare>();
+}
+
+void tst_QFlatMap::transparency_struct()
+{
+ struct StringViewCompare
+ {
+ struct is_transparent {};
+ bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
+ {
+ return lhs < rhs;
+ }
+ };
+ transparency_impl<StringViewCompare>();
+}
+
+template <typename StringViewCompare>
+void tst_QFlatMap::transparency_impl()
+{
+ using Map = QFlatMap<QString, QString, StringViewCompare>;
+ auto m = Map{ { "one", "een" }, { "two", "twee" }, { "three", "dree" } };
+
+ const QString numbers = "one two three";
+ const QStringView sv1{numbers.constData(), 3};
+ const QStringView sv2{numbers.constData() + 4, 3};
+ const QStringView sv3{numbers.constData() + 8, 5};
+ QCOMPARE(m.lower_bound(sv1).value(), "een");
+ QCOMPARE(m.value(sv1), "een");
+ QCOMPARE(m.lower_bound(sv2).value(), "twee");
+ QCOMPARE(m.value(sv2), "twee");
+ QCOMPARE(m.lower_bound(sv3).value(), "dree");
+ QCOMPARE(m.value(sv3), "dree");
+
+ QVERIFY(m.contains(sv2));
+ auto twee = m.take(sv2);
+ static_assert(std::is_same_v<decltype(twee), QString>);
+ QCOMPARE(twee, "twee");
+ QVERIFY(!m.contains(sv2));
+
+ QVERIFY(m.contains(QLatin1String("one")));
+ QVERIFY(m.remove(QAnyStringView(u8"one")));
+ QVERIFY(!m.contains(QLatin1String("one")));
+}
+
+void tst_QFlatMap::try_emplace_and_insert_or_assign()
+{
+ using Map = QFlatMap<QByteArray, QByteArray>;
+
+ const QByteArray foo = QByteArrayLiteral("foo");
+ const qsizetype qqq_1 = 3;
+ const char qqq_2 = 'q';
+ const QByteArray qqq = QByteArray(qqq_1, qqq_2);
+
+ auto sb = [] (const auto &str) { return str % ""; };
+ auto rvalue = [](const auto &x) { return x; };
+#define lvalue(x) x
+#define CHECKS() \
+ do { \
+ QVERIFY(!m.try_emplace(rvalue(foo), lvalue(foo)).second); \
+ QCOMPARE(m.value(foo), qqq); \
+ QVERIFY(!m.try_emplace(lvalue(foo), lvalue(foo)).second); \
+ QCOMPARE(m.value(foo), qqq); \
+ QVERIFY(!m.try_emplace(lvalue(foo), sb(foo)).second); \
+ QCOMPARE(m.value(foo), qqq); \
+ QVERIFY(!m.try_emplace(rvalue(foo), sb(foo)).second); \
+ QCOMPARE(m.value(foo), qqq); \
+ } while (0) \
+ /* end */
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(lvalue(foo), lvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(lvalue(foo), lvalue(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(lvalue(foo), lvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.try_emplace(lvalue(foo), lvalue(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(lvalue(foo), rvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(lvalue(foo), rvalue(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(lvalue(foo), rvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.try_emplace(lvalue(foo), rvalue(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(lvalue(foo), qqq_1, qqq_2).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(lvalue(foo), sb(qqq)).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(lvalue(foo), sb(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(lvalue(foo), sb(qqq)).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ QVERIFY(!m.try_emplace(lvalue(foo), sb(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(rvalue(foo), lvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(rvalue(foo), lvalue(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(rvalue(foo), lvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.try_emplace(rvalue(foo), lvalue(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(rvalue(foo), rvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(rvalue(foo), rvalue(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(rvalue(foo), rvalue(qqq)).second);
+ CHECKS();
+ QVERIFY(!m.try_emplace(rvalue(foo), rvalue(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(rvalue(foo), qqq_1, qqq_2).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ }
+
+ {
+ Map m;
+ QVERIFY(m.try_emplace(rvalue(foo), sb(qqq)).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ QVERIFY(!m.insert_or_assign(rvalue(foo), sb(foo)).second);
+ QCOMPARE(m.value(foo), foo);
+ }
+
+ {
+ Map m;
+ QVERIFY(m.insert_or_assign(rvalue(foo), sb(qqq)).second);
+ QCOMPARE(m.value(foo), qqq);
+ CHECKS();
+ QVERIFY(!m.try_emplace(rvalue(foo), sb(foo)).second);
+ QCOMPARE(m.value(foo), qqq);
+ }
+#undef CHECKS
+#undef lvalue
+}
+
+void tst_QFlatMap::viewIterators()
+{
+ using Map = QFlatMap<QByteArray, QByteArray>;
+ Map m({ { "yksi", "een"}, { "kaksi", "twee" }, { "kolme", "dree" } });
+ {
+ std::vector<QByteArray> keys;
+ std::transform(m.begin(), m.end(), std::back_inserter(keys),
+ [](const Map::value_type &v)
+ {
+ return v.first;
+ });
+ auto it = keys.begin();
+ QCOMPARE(*it, "kaksi");
+ QCOMPARE(it->size(), 5);
+ ++it;
+ QCOMPARE(*it, "kolme");
+ it++;
+ QCOMPARE(*it, "yksi");
+ ++it;
+ QCOMPARE(it, keys.end());
+ --it;
+ QCOMPARE(*it, "yksi");
+ it--;
+ QCOMPARE(*it, "kolme");
+ }
+ {
+ std::vector<QByteArray> values;
+ std::transform(m.begin(), m.end(), std::back_inserter(values),
+ [](const Map::value_type &v)
+ {
+ return v.second;
+ });
+ auto it = values.begin();
+ QCOMPARE(*it, "twee");
+ QCOMPARE(it->size(), 4);
+ ++it;
+ QCOMPARE(*it, "dree");
+ it++;
+ QCOMPARE(*it, "een");
+ ++it;
+ QCOMPARE(it, values.end());
+ --it;
+ QCOMPARE(*it, "een");
+ it--;
+ QCOMPARE(*it, "dree");
+ }
+}
+
+void tst_QFlatMap::varLengthArray()
+{
+ using Map = QVarLengthFlatMap<int, QByteArray, 1024>;
+ Map m(Qt::OrderedUniqueRange, { { 2, "twee" } });
+ m.insert_or_assign(1, "een");
+ m.remove(1);
+ QVERIFY(!m.isEmpty());
+ m.remove(2);
+ QVERIFY(m.isEmpty());
+}
+
+QTEST_APPLESS_MAIN(tst_QFlatMap)
+#include "tst_qflatmap.moc"
diff --git a/tests/auto/corelib/tools/qfreelist/CMakeLists.txt b/tests/auto/corelib/tools/qfreelist/CMakeLists.txt
new file mode 100644
index 0000000000..a37d3131f5
--- /dev/null
+++ b/tests/auto/corelib/tools/qfreelist/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qfreelist Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qfreelist LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qfreelist
+ SOURCES
+ tst_qfreelist.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qfreelist/qfreelist.pro b/tests/auto/corelib/tools/qfreelist/qfreelist.pro
deleted file mode 100644
index 4825987bcf..0000000000
--- a/tests/auto/corelib/tools/qfreelist/qfreelist.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qfreelist
-QT = core-private testlib
-SOURCES = tst_qfreelist.cpp
-!qtConfig(private_tests): SOURCES += $$QT_SOURCE_TREE/src/corelib/tools/qfreelist.cpp
diff --git a/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp b/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp
index a09bcd5121..a45fa6d400 100644
--- a/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp
+++ b/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp
@@ -1,38 +1,12 @@
-/****************************************************************************
-**
-** 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 <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
#include <QtCore/QList>
#include <QtCore/QThread>
#include <private/qfreelist_p.h>
-#include <QtTest/QtTest>
+#include <QTest>
class tst_QFreeList : public QObject
{
@@ -120,7 +94,7 @@ class FreeListThread : public QThread
public:
inline FreeListThread() : QThread() { }
- inline void run()
+ inline void run() override
{
QElapsedTimer t;
t.start();
@@ -141,7 +115,7 @@ public:
needToRelease << i;
} while (t.elapsed() < TimeLimit);
- foreach (int x, needToRelease)
+ for (int x : std::as_const(needToRelease))
freelist.release(x);
}
};
diff --git a/tests/auto/corelib/tools/qhash/CMakeLists.txt b/tests/auto/corelib/tools/qhash/CMakeLists.txt
new file mode 100644
index 0000000000..8702b8bf23
--- /dev/null
+++ b/tests/auto/corelib/tools/qhash/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qhash Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qhash LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qhash
+ SOURCES
+ tst_qhash.cpp
+)
+
+qt_internal_undefine_global_definition(tst_qhash QT_NO_JAVA_STYLE_ITERATORS)
diff --git a/tests/auto/corelib/tools/qhash/qhash.pro b/tests/auto/corelib/tools/qhash/qhash.pro
deleted file mode 100644
index e96c0d1bf1..0000000000
--- a/tests/auto/corelib/tools/qhash/qhash.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qhash
-QT = core testlib
-SOURCES = $$PWD/tst_qhash.cpp
-
-DEFINES -= QT_NO_JAVA_STYLE_ITERATORS
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index 91cd3eb0bd..b3dbdfa40c 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -1,38 +1,22 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <QTest>
+
+#include <qdebug.h>
#include <qhash.h>
#include <qmap.h>
+#include <qscopeguard.h>
+#include <qset.h>
#include <algorithm>
#include <vector>
+#include <unordered_set>
+#include <string>
+
+#include <qsemaphore.h>
+
+using namespace Qt::StringLiterals;
class tst_QHash : public QObject
{
@@ -40,7 +24,9 @@ class tst_QHash : public QObject
private slots:
void insert1();
void erase();
+ void erase_edge_case();
void key();
+ void keys();
void swap();
void count(); // copied from tst_QMap
@@ -52,17 +38,36 @@ private slots:
void qhash();
void take(); // copied from tst_QMap
void operator_eq(); // slightly modified from tst_QMap
+ void heterogeneousSearch();
+ void heterogeneousSearchConstKey();
+ void heterogeneousSearchByteArray();
+ void heterogeneousSearchString();
+ void heterogeneousSearchLatin1String();
+
void rehash_isnt_quadratic();
void dont_need_default_constructor();
void qmultihash_specific();
+ void qmultihash_qhash_rvalue_ref_ctor();
+ void qmultihash_qhash_rvalue_ref_unite();
+ void qmultihashUnite();
+ void qmultihashSize();
+ void qmultihashHeterogeneousSearch();
+ void qmultihashHeterogeneousSearchConstKey();
+ void qmultihashHeterogeneousSearchByteArray();
+ void qmultihashHeterogeneousSearchString();
+ void qmultihashHeterogeneousSearchLatin1String();
void compare();
void compare2();
void iterators(); // sligthly modified from tst_QMap
+ void multihashIterators();
+ void iteratorsInEmptyHash();
void keyIterator();
+ void multihashKeyIterator();
void keyValueIterator();
+ void multihashKeyValueIterator();
+ void keyValueIteratorInEmptyHash();
void keys_values_uniqueKeys(); // slightly modified from tst_QMap
- void noNeedlessRehashes();
void const_shared_null();
void twoArguments_qHash();
@@ -70,13 +75,40 @@ private slots:
void eraseValidIteratorOnSharedHash();
void equal_range();
void insert_hash();
+ void multiHashStoresInReverseInsertionOrder();
+
+ void emplace();
+
+ void badHashFunction();
+ void hashOfHash();
+
+ void stdHash();
+
+ void countInEmptyHash();
+ void removeInEmptyHash();
+ void valueInEmptyHash();
+ void fineTuningInEmptyHash();
+
+ void reserveShared();
+ void reserveLessThanCurrentAmount();
+ void reserveKeepCapacity_data();
+ void reserveKeepCapacity();
+
+ void QTBUG98265();
+
+ void detachAndReferences();
+
+ void lookupUsingKeyIterator();
+
+ void squeeze();
+ void squeezeShared();
};
struct IdentityTracker {
int value, id;
};
-inline uint qHash(IdentityTracker key) { return qHash(key.value); }
+inline size_t qHash(IdentityTracker key) { return qHash(key.value); }
inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
@@ -85,6 +117,8 @@ struct Foo {
Foo():c(count) { ++count; }
Foo(const Foo& o):c(o.c) { ++count; }
~Foo() { --count; }
+ constexpr Foo &operator=(const Foo &o) noexcept { c = o.c; return *this; }
+
int c;
int data[8];
};
@@ -95,26 +129,53 @@ int Foo::count = 0;
class MyClass
{
public:
- MyClass() { ++count;
+ MyClass()
+ {
+ ++count;
}
- MyClass( const QString& c) {
- count++; str = c;
+ MyClass( const QString& c)
+ {
+ count++;
+ str = c;
+ }
+ MyClass(const QString &a, const QString &b)
+ {
+ count++;
+ str = a + b;
}
~MyClass() {
count--;
}
MyClass( const MyClass& c ) {
- count++; str = c.str;
+ count++;
+ ++copies;
+ str = c.str;
}
MyClass &operator =(const MyClass &o) {
- str = o.str; return *this;
+ str = o.str;
+ ++copies;
+ return *this;
+ }
+ MyClass(MyClass &&c) {
+ count++;
+ ++moves;
+ str = c.str;
+ }
+ MyClass &operator =(MyClass &&o) {
+ str = o.str;
+ ++moves;
+ return *this;
}
QString str;
static int count;
+ static int copies;
+ static int moves;
};
-int MyClass::count = 0;
+int MyClass::count = 0;
+int MyClass::copies = 0;
+int MyClass::moves = 0;
typedef QHash<QString, MyClass> MyMap;
@@ -124,13 +185,13 @@ void tst_QHash::count()
{
MyMap map;
MyMap map2( map );
- QCOMPARE( map.count(), 0 );
- QCOMPARE( map2.count(), 0 );
+ QCOMPARE( map.size(), 0 );
+ QCOMPARE( map2.size(), 0 );
QCOMPARE( MyClass::count, 0 );
// detach
map2["Hallo"] = MyClass( "Fritz" );
- QCOMPARE( map.count(), 0 );
- QCOMPARE( map2.count(), 1 );
+ QCOMPARE( map.size(), 0 );
+ QCOMPARE( map2.size(), 1 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 1 );
#endif
@@ -140,11 +201,11 @@ void tst_QHash::count()
{
typedef QHash<QString, MyClass> Map;
Map map;
- QCOMPARE( map.count(), 0);
+ QCOMPARE( map.size(), 0);
map.insert( "Torben", MyClass("Weis") );
- QCOMPARE( map.count(), 1 );
+ QCOMPARE( map.size(), 1 );
map.insert( "Claudia", MyClass("Sorg") );
- QCOMPARE( map.count(), 2 );
+ QCOMPARE( map.size(), 2 );
map.insert( "Lars", MyClass("Linzbach") );
map.insert( "Matthias", MyClass("Ettrich") );
map.insert( "Sue", MyClass("Paludo") );
@@ -152,7 +213,7 @@ void tst_QHash::count()
map.insert( "Haavard", MyClass("Nord") );
map.insert( "Arnt", MyClass("Gulbrandsen") );
map.insert( "Paul", MyClass("Tvete") );
- QCOMPARE( map.count(), 9 );
+ QCOMPARE( map.size(), 9 );
map.insert( "Paul", MyClass("Tvete 1") );
map.insert( "Paul", MyClass("Tvete 2") );
map.insert( "Paul", MyClass("Tvete 3") );
@@ -160,68 +221,68 @@ void tst_QHash::count()
map.insert( "Paul", MyClass("Tvete 5") );
map.insert( "Paul", MyClass("Tvete 6") );
- QCOMPARE( map.count(), 9 );
+ QCOMPARE( map.size(), 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
Map map2( map );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.insert( "Kay", MyClass("Roemer") );
- QVERIFY( map2.count() == 10 );
- QVERIFY( map.count() == 9 );
+ QVERIFY( map2.size() == 10 );
+ QVERIFY( map.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 19 );
#endif
map2 = map;
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.insert( "Kay", MyClass("Roemer") );
- QVERIFY( map2.count() == 10 );
+ QVERIFY( map2.size() == 10 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 19 );
#endif
map2.clear();
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2 = map;
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.clear();
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map.remove( "Lars" );
- QVERIFY( map.count() == 8 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 8 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 8 );
#endif
map.remove( "Mist" );
- QVERIFY( map.count() == 8 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 8 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 8 );
#endif
@@ -235,22 +296,22 @@ void tst_QHash::count()
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 1 );
#endif
- QVERIFY( map.count() == 1 );
+ QVERIFY( map.size() == 1 );
(void)map["Torben"].str;
(void)map["Lars"].str;
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 2 );
#endif
- QVERIFY( map.count() == 2 );
+ QVERIFY( map.size() == 2 );
const Map& cmap = map;
(void)cmap["Depp"].str;
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 2 );
#endif
- QVERIFY( map.count() == 2 );
- QVERIFY( cmap.count() == 2 );
+ QVERIFY( map.size() == 2 );
+ QVERIFY( cmap.size() == 2 );
}
QCOMPARE( MyClass::count, 0 );
{
@@ -276,17 +337,17 @@ void tst_QHash::insert1()
Hash hash;
QString key = QLatin1String(" ");
for (int i = 0; i < 10; ++i) {
- key[0] = i + '0';
+ key[0] = QChar(i + '0');
for (int j = 0; j < 10; ++j) {
- key[1] = j + '0';
+ key[1] = QChar(j + '0');
hash.insert(key, "V" + key);
}
}
for (int i = 0; i < 10; ++i) {
- key[0] = i + '0';
+ key[0] = QChar(i + '0');
for (int j = 0; j < 10; ++j) {
- key[1] = j + '0';
+ key[1] = QChar(j + '0');
hash.remove(key);
}
}
@@ -301,6 +362,8 @@ void tst_QHash::insert1()
QVERIFY(hash.size() == 2);
QVERIFY(!hash.isEmpty());
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
{
Hash hash2 = hash;
hash2 = hash;
@@ -313,6 +376,7 @@ void tst_QHash::insert1()
QVERIFY(hash2.isEmpty());
}
QVERIFY(hash.size() == 2);
+QT_WARNING_POP
{
Hash hash2 = hash;
@@ -442,6 +506,7 @@ void tst_QHash::insert1()
{
QHash<IdentityTracker, int> hash;
QCOMPARE(hash.size(), 0);
+ QVERIFY(!hash.isDetached());
const int dummy = -1;
IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
QCOMPARE(hash.insert(id00, id00.id).key().id, id00.id);
@@ -451,20 +516,6 @@ void tst_QHash::insert1()
QCOMPARE(hash.find(searchKey).value(), id01.id); // last-inserted value
QCOMPARE(hash.find(searchKey).key().id, id00.id); // but first-inserted key
}
- {
- QMultiHash<IdentityTracker, int> hash;
- QCOMPARE(hash.size(), 0);
- const int dummy = -1;
- IdentityTracker id00 = {0, 0}, id01 = {0, 1}, searchKey = {0, dummy};
- QCOMPARE(hash.insert(id00, id00.id).key().id, id00.id);
- QCOMPARE(hash.size(), 1);
- QCOMPARE(hash.insert(id01, id01.id).key().id, id01.id);
- QCOMPARE(hash.size(), 2);
- QMultiHash<IdentityTracker, int>::const_iterator pos = hash.constFind(searchKey);
- QCOMPARE(pos.value(), pos.key().id); // key fits to value it was inserted with
- ++pos;
- QCOMPARE(pos.value(), pos.key().id); // key fits to value it was inserted with
- }
}
void tst_QHash::erase()
@@ -491,13 +542,75 @@ void tst_QHash::erase()
++n;
}
QVERIFY(n == 3);
- QHash<int, int> h2;
- h2.insertMulti(20, 41);
- h2.insertMulti(20, 42);
+
+ QMultiHash<int, int> h2;
+ h2.insert(20, 41);
+ h2.insert(20, 42);
QVERIFY(h2.size() == 2);
- it1 = h2.erase(h2.begin());
- it1 = h2.erase(h2.begin());
- QVERIFY(it1 == h2.end());
+ auto bit = h2.begin();
+ auto mit = h2.erase(bit);
+ mit = h2.erase(h2.begin());
+ QVERIFY(mit == h2.end());
+
+ h2 = QMultiHash<int, int>();
+ h2.emplace(1, 1);
+ h2.emplace(1, 2);
+ h2.emplace(3, 1);
+ h2.emplace(3, 4);
+ QMultiHash<int, int> h3 = h2;
+ auto it = h3.constFind(3);
+ ++it;
+ QVERIFY(h3.isSharedWith(h2));
+ it = h3.erase(it);
+ QVERIFY(!h3.isSharedWith(h2));
+ if (it != h3.cend()) {
+ auto it2 = h3.constFind(it.key());
+ QCOMPARE(it, it2);
+ }
+}
+
+/*
+ With a specific seed we could end up in a situation where, upon deleting the
+ last entry in a QHash, the returned iterator would not point to the end()
+ iterator.
+*/
+void tst_QHash::erase_edge_case()
+{
+ QHashSeed::setDeterministicGlobalSeed();
+ auto resetSeed = qScopeGuard([&]() {
+ QHashSeed::resetRandomGlobalSeed();
+ });
+
+ QHash<int, int> h1;
+ h1.reserve(2);
+ qsizetype capacity = h1.capacity();
+ // Beholden to QHash internals:
+ qsizetype numBuckets = capacity << 1;
+
+ // Find some keys which will both be slotted into the last bucket:
+ int keys[2];
+ int index = 0;
+ for (qsizetype i = 0; i < numBuckets * 4 && index < 2; ++i) {
+ const size_t hash = qHash(i, QHashSeed::globalSeed());
+ const size_t bucketForHash = QHashPrivate::GrowthPolicy::bucketForHash(numBuckets, hash);
+ if (qsizetype(bucketForHash) == numBuckets - 1)
+ keys[index++] = i;
+ }
+ QCOMPARE(index, 2); // Sanity check. If this fails then the test needs an update!
+
+ // As mentioned earlier these are both calculated to be in the last bucket:
+ h1.insert(keys[0], 4);
+ h1.insert(keys[1], 6);
+ // As a sanity-check, make sure that the key we inserted last is the first one (because its
+ // allocation to the last bucket would make it wrap around):
+ // NOTE: If this fails this then this test may need an update!!!
+ QCOMPARE(h1.constBegin().key(), keys[1]);
+ // Then we delete the last entry:
+ QHash<int, int>::iterator it1 = h1.begin();
+ ++it1;
+ it1 = h1.erase(it1);
+ // Now, since we deleted the last entry, the iterator should be at the end():
+ QVERIFY(it1 == h1.end());
}
void tst_QHash::key()
@@ -508,6 +621,7 @@ void tst_QHash::key()
QHash<QString, int> hash1;
QCOMPARE(hash1.key(1), QString());
QCOMPARE(hash1.key(1, def), def);
+ QVERIFY(!hash1.isDetached());
hash1.insert("one", 1);
QCOMPARE(hash1.key(1), QLatin1String("one"));
@@ -538,6 +652,7 @@ void tst_QHash::key()
QHash<int, QString> hash2;
QCOMPARE(hash2.key("one"), 0);
QCOMPARE(hash2.key("one", def), def);
+ QVERIFY(!hash2.isDetached());
hash2.insert(1, "one");
QCOMPARE(hash2.key("one"), 1);
@@ -569,6 +684,62 @@ void tst_QHash::key()
QCOMPARE(hash2.key("zero"), 0);
QCOMPARE(hash2.key("zero", def), 0);
}
+
+ {
+ const int def = -1;
+ QMultiHash<int, QString> hash;
+ QCOMPARE(hash.key("val"), 0);
+ QCOMPARE(hash.key("val", def), def);
+ QVERIFY(!hash.isDetached());
+
+ hash.insert(1, "value1");
+ hash.insert(1, "value2");
+ hash.insert(2, "value1");
+
+ QCOMPARE(hash.key("value2"), 1);
+ const auto key = hash.key("value1");
+ QVERIFY(key == 1 || key == 2);
+ QCOMPARE(hash.key("value"), 0);
+ QCOMPARE(hash.key("value", def), def);
+ }
+}
+
+template <typename T>
+QList<T> sorted(const QList<T> &list)
+{
+ QList<T> res = list;
+ std::sort(res.begin(), res.end());
+ return res;
+}
+
+void tst_QHash::keys()
+{
+ {
+ QHash<QString, int> hash;
+ QVERIFY(hash.keys().isEmpty());
+ QVERIFY(hash.keys(1).isEmpty());
+ QVERIFY(!hash.isDetached());
+
+ hash.insert("key1", 1);
+ hash.insert("key2", 2);
+ hash.insert("key3", 1);
+
+ QCOMPARE(sorted(hash.keys()), QStringList({ "key1", "key2", "key3" }));
+ QCOMPARE(sorted(hash.keys(1)), QStringList({ "key1", "key3" }));
+ }
+ {
+ QMultiHash<QString, int> hash;
+ QVERIFY(hash.keys().isEmpty());
+ QVERIFY(hash.keys(1).isEmpty());
+ QVERIFY(!hash.isDetached());
+
+ hash.insert("key1", 1);
+ hash.insert("key2", 1);
+ hash.insert("key1", 2);
+
+ QCOMPARE(sorted(hash.keys()), QStringList({ "key1", "key1", "key2" }));
+ QCOMPARE(sorted(hash.keys(1)), QStringList({ "key1", "key2" }));
+ }
}
void tst_QHash::swap()
@@ -598,6 +769,25 @@ void tst_QHash::clear()
QVERIFY( map.isEmpty() );
}
QCOMPARE( MyClass::count, int(0) );
+
+ {
+ QMultiHash<QString, MyClass> multiHash;
+ multiHash.clear();
+ QVERIFY(multiHash.isEmpty());
+
+ multiHash.insert("key", MyClass("value0"));
+ QVERIFY(!multiHash.isEmpty());
+ multiHash.clear();
+ QVERIFY(multiHash.isEmpty());
+
+ multiHash.insert("key0", MyClass("value0"));
+ multiHash.insert("key0", MyClass("value1"));
+ multiHash.insert("key1", MyClass("value2"));
+ QVERIFY(!multiHash.isEmpty());
+ multiHash.clear();
+ QVERIFY(multiHash.isEmpty());
+ }
+ QCOMPARE(MyClass::count, int(0));
}
//copied from tst_QMap
void tst_QHash::empty()
@@ -605,24 +795,31 @@ void tst_QHash::empty()
QHash<int, QString> map1;
QVERIFY(map1.isEmpty());
+ QVERIFY(map1.empty());
map1.insert(1, "one");
QVERIFY(!map1.isEmpty());
+ QVERIFY(!map1.empty());
map1.clear();
QVERIFY(map1.isEmpty());
-
+ QVERIFY(map1.empty());
}
//copied from tst_QMap
void tst_QHash::find()
{
+ const QHash<int, QString> constEmptyHash;
+ QVERIFY(constEmptyHash.find(1) == constEmptyHash.end());
+ QVERIFY(!constEmptyHash.isDetached());
+
QHash<int, QString> map1;
QString testString="Teststring %0";
QString compareString;
int i,count=0;
QVERIFY(map1.find(1) == map1.end());
+ QVERIFY(!map1.isDetached());
map1.insert(1,"Mensch");
map1.insert(1,"Mayer");
@@ -631,14 +828,25 @@ void tst_QHash::find()
QCOMPARE(map1.find(1).value(), QLatin1String("Mayer"));
QCOMPARE(map1.find(2).value(), QLatin1String("Hej"));
- for(i = 3; i < 10; ++i) {
+ const QMultiHash<int, QString> constEmptyMultiHash;
+ QVERIFY(constEmptyMultiHash.find(1) == constEmptyMultiHash.cend());
+ QVERIFY(constEmptyMultiHash.find(1, "value") == constEmptyMultiHash.cend());
+ QVERIFY(!constEmptyMultiHash.isDetached());
+
+ QMultiHash<int, QString> emptyMultiHash;
+ QVERIFY(emptyMultiHash.find(1) == emptyMultiHash.end());
+ QVERIFY(emptyMultiHash.find(1, "value") == emptyMultiHash.end());
+ QVERIFY(!emptyMultiHash.isDetached());
+
+ QMultiHash<int, QString> multiMap(map1);
+ for (i = 3; i < 10; ++i) {
compareString = testString.arg(i);
- map1.insertMulti(4, compareString);
+ multiMap.insert(4, compareString);
}
- QHash<int, QString>::const_iterator it=map1.constFind(4);
+ auto it = multiMap.constFind(4);
- for(i = 9; i > 2 && it != map1.constEnd() && it.key() == 4; --i) {
+ for (i = 9; i > 2 && it != multiMap.constEnd() && it.key() == 4; --i) {
compareString = testString.arg(i);
QVERIFY(it.value() == compareString);
++it;
@@ -656,6 +864,7 @@ void tst_QHash::constFind()
int i,count=0;
QVERIFY(map1.constFind(1) == map1.constEnd());
+ QVERIFY(!map1.isDetached());
map1.insert(1,"Mensch");
map1.insert(1,"Mayer");
@@ -664,14 +873,19 @@ void tst_QHash::constFind()
QCOMPARE(map1.constFind(1).value(), QLatin1String("Mayer"));
QCOMPARE(map1.constFind(2).value(), QLatin1String("Hej"));
- for(i = 3; i < 10; ++i) {
+ QMultiHash<int, QString> emptyMultiHash;
+ QVERIFY(emptyMultiHash.constFind(1) == emptyMultiHash.constEnd());
+ QVERIFY(!emptyMultiHash.isDetached());
+
+ QMultiHash<int, QString> multiMap(map1);
+ for (i = 3; i < 10; ++i) {
compareString = testString.arg(i);
- map1.insertMulti(4, compareString);
+ multiMap.insert(4, compareString);
}
- QHash<int, QString>::const_iterator it=map1.constFind(4);
+ auto it = multiMap.constFind(4);
- for(i = 9; i > 2 && it != map1.constEnd() && it.key() == 4; --i) {
+ for (i = 9; i > 2 && it != multiMap.constEnd() && it.key() == 4; --i) {
compareString = testString.arg(i);
QVERIFY(it.value() == compareString);
++it;
@@ -686,12 +900,15 @@ void tst_QHash::contains()
QHash<int, QString> map1;
int i;
+ QVERIFY(!map1.contains(1));
+ QVERIFY(!map1.isDetached());
+
map1.insert(1, "one");
QVERIFY(map1.contains(1));
- for(i=2; i < 100; ++i)
+ for (i=2; i < 100; ++i)
map1.insert(i, "teststring");
- for(i=99; i > 1; --i)
+ for (i=99; i > 1; --i)
QVERIFY(map1.contains(i));
map1.remove(43);
@@ -704,16 +921,31 @@ class QGlobalQHashSeedResetter
int oldSeed;
public:
// not entirely correct (may lost changes made by another thread between the query
- // of the old and the setting of the new seed), but qSetGlobalQHashSeed doesn't
+ // of the old and the setting of the new seed), but setHashSeed() can't
// return the old value, so this is the best we can do:
explicit QGlobalQHashSeedResetter(int newSeed)
- : oldSeed(qGlobalQHashSeed())
+ : oldSeed(getHashSeed())
{
- qSetGlobalQHashSeed(newSeed);
+ setHashSeed(newSeed);
}
~QGlobalQHashSeedResetter()
{
- qSetGlobalQHashSeed(oldSeed);
+ setHashSeed(oldSeed);
+ }
+
+private:
+ // The functions are implemented to replace the deprecated
+ // qGlobalQHashSeed() and qSetGlobalQHashSeed()
+ static int getHashSeed()
+ {
+ return int(QHashSeed::globalSeed() & INT_MAX);
+ }
+ static void setHashSeed(int seed)
+ {
+ if (seed == 0)
+ QHashSeed::setDeterministicGlobalSeed();
+ else
+ QHashSeed::resetRandomGlobalSeed();
}
};
@@ -764,13 +996,33 @@ void tst_QHash::qhash()
//copied from tst_QMap
void tst_QHash::take()
{
- QHash<int, QString> map;
+ {
+ QHash<int, QString> map;
+ QCOMPARE(map.take(1), QString());
+ QVERIFY(!map.isDetached());
+
+ map.insert(2, "zwei");
+ map.insert(3, "drei");
- map.insert(2, "zwei");
- map.insert(3, "drei");
+ QCOMPARE(map.take(3), QLatin1String("drei"));
+ QVERIFY(!map.contains(3));
+ }
+ {
+ QMultiHash<int, QString> hash;
+ QCOMPARE(hash.take(1), QString());
+ QVERIFY(!hash.isDetached());
- QCOMPARE(map.take(3), QLatin1String("drei"));
- QVERIFY(!map.contains(3));
+ hash.insert(1, "value1");
+ hash.insert(2, "value2");
+ hash.insert(1, "value3");
+
+ // The docs tell that if there are multiple values for a key, then the
+ // most recent is returned.
+ QCOMPARE(hash.take(1), "value3");
+ QCOMPARE(hash.take(1), "value1");
+ QCOMPARE(hash.take(1), QString());
+ QCOMPARE(hash.take(2), "value2");
+ }
}
// slightly modified from tst_QMap
@@ -855,33 +1107,33 @@ void tst_QHash::operator_eq()
// regardless of insertion or iteration order
{
- QHash<int, int> a;
- QHash<int, int> b;
+ QMultiHash<int, int> a;
+ QMultiHash<int, int> b;
- a.insertMulti(0, 0);
- a.insertMulti(0, 1);
+ a.insert(0, 0);
+ a.insert(0, 1);
- b.insertMulti(0, 1);
- b.insertMulti(0, 0);
+ b.insert(0, 1);
+ b.insert(0, 0);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
- QHash<int, int> a;
- QHash<int, int> b;
+ QMultiHash<int, int> a;
+ QMultiHash<int, int> b;
enum { Count = 100 };
for (int key = 0; key < Count; ++key) {
for (int value = 0; value < Count; ++value)
- a.insertMulti(key, value);
+ a.insert(key, value);
}
for (int key = Count - 1; key >= 0; --key) {
for (int value = 0; value < Count; ++value)
- b.insertMulti(key, value);
+ b.insert(key, value);
}
QVERIFY(a == b);
@@ -889,8 +1141,8 @@ void tst_QHash::operator_eq()
}
{
- QHash<int, int> a;
- QHash<int, int> b;
+ QMultiHash<int, int> a;
+ QMultiHash<int, int> b;
enum {
Count = 100,
@@ -900,7 +1152,7 @@ void tst_QHash::operator_eq()
for (int key = 0; key < Count; ++key) {
for (int value = 0; value < Count; ++value)
- a.insertMulti(key, value);
+ a.insert(key, value);
}
// Generates two permutations of [0, Count) for the keys and values,
@@ -909,7 +1161,7 @@ void tst_QHash::operator_eq()
for (int k = 0; k < Count; ++k) {
const int key = (k * KeyStep) % Count;
for (int v = 0; v < Count; ++v)
- b.insertMulti(key, (v * ValueStep) % Count);
+ b.insert(key, (v * ValueStep) % Count);
}
QVERIFY(a == b);
@@ -917,16 +1169,232 @@ void tst_QHash::operator_eq()
}
}
+#ifdef __cpp_concepts
+struct HeterogeneousHashingType
+{
+ inline static int conversionCount = 0;
+ QString s;
+
+ Q_IMPLICIT operator QString() const
+ {
+ ++conversionCount;
+ return s;
+ }
+
+ // std::equality_comparable_with requires we be self-comparable too
+ friend bool operator==(const HeterogeneousHashingType &t1, const HeterogeneousHashingType &t2) = default;
+
+ friend bool operator==(const QString &string, const HeterogeneousHashingType &tester)
+ { return tester.s == string; }
+ friend bool operator!=(const QString &string, const HeterogeneousHashingType &tester)
+ { return !(tester.s == string); }
+
+ friend size_t qHash(const HeterogeneousHashingType &tester, size_t seed)
+ { return qHash(tester.s, seed); }
+};
+QT_BEGIN_NAMESPACE
+template <> struct QHashHeterogeneousSearch<QString, HeterogeneousHashingType> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<HeterogeneousHashingType, QString> : std::true_type {};
+QT_END_NAMESPACE
+static_assert(std::is_same_v<QString, std::common_type_t<QString, HeterogeneousHashingType>>);
+static_assert(std::equality_comparable_with<QString, HeterogeneousHashingType>);
+static_assert(QHashPrivate::HeterogeneouslySearchableWith<QString, HeterogeneousHashingType>);
+static_assert(QHashPrivate::HeterogeneouslySearchableWith<HeterogeneousHashingType, QString>);
+
+template <typename T> struct HeterogeneousSearchTestHelper
+{
+ static void resetCounter() {}
+ static void checkCounter() {}
+};
+template <> struct HeterogeneousSearchTestHelper<HeterogeneousHashingType>
+{
+ static void resetCounter()
+ {
+ HeterogeneousHashingType::conversionCount = 0;
+ }
+ static void checkCounter()
+ {
+ QTest::setThrowOnFail(true);
+ auto scopeExit = qScopeGuard([] { QTest::setThrowOnFail(false); });
+ QCOMPARE(HeterogeneousHashingType::conversionCount, 0);
+ }
+};
+#else
+using HeterogeneousHashingType = QString;
+#endif
+
+template <template <typename, typename> class Hash, typename String, typename View, typename Converter>
+static void heterogeneousSearchTest(const QList<std::remove_const_t<String>> &keys, Converter conv)
+{
+#ifdef __cpp_concepts
+ using Helper = HeterogeneousSearchTestHelper<View>;
+ String key = keys.last();
+ String otherKey = keys.first();
+ auto keyHolder = conv(key);
+ auto otherKeyHolder = conv(otherKey);
+ View keyView(keyHolder);
+ View otherKeyView(otherKeyHolder);
+
+ Hash<String, qsizetype> hash;
+ static constexpr bool IsMultiHash = !std::is_same_v<decltype(hash.remove(String())), bool>;
+ hash[key] = keys.size();
+
+ Helper::resetCounter();
+ QVERIFY(hash.contains(keyView));
+ QCOMPARE_EQ(hash.count(keyView), 1);
+ QCOMPARE_EQ(hash.value(keyView), keys.size());
+ QCOMPARE_EQ(hash.value(keyView, -1), keys.size());
+ QCOMPARE_EQ(std::as_const(hash)[keyView], keys.size());
+ QCOMPARE_EQ(hash.find(keyView), hash.begin());
+ QCOMPARE_EQ(std::as_const(hash).find(keyView), hash.constBegin());
+ QCOMPARE_EQ(hash.constFind(keyView), hash.constBegin());
+ QCOMPARE_EQ(hash.equal_range(keyView), std::make_pair(hash.begin(), hash.end()));
+ QCOMPARE_EQ(std::as_const(hash).equal_range(keyView),
+ std::make_pair(hash.constBegin(), hash.constEnd()));
+ Helper::checkCounter();
+
+ QVERIFY(!hash.contains(otherKeyView));
+ QCOMPARE_EQ(hash.count(otherKeyView), 0);
+ QCOMPARE_EQ(hash.value(otherKeyView), 0);
+ QCOMPARE_EQ(hash.value(otherKeyView, -1), -1);
+ QCOMPARE_EQ(std::as_const(hash)[otherKeyView], 0);
+ QCOMPARE_EQ(hash.find(otherKeyView), hash.end());
+ QCOMPARE_EQ(std::as_const(hash).find(otherKeyView), hash.constEnd());
+ QCOMPARE_EQ(hash.constFind(otherKeyView), hash.constEnd());
+ QCOMPARE_EQ(hash.equal_range(otherKeyView), std::make_pair(hash.end(), hash.end()));
+ QCOMPARE_EQ(std::as_const(hash).equal_range(otherKeyView),
+ std::make_pair(hash.constEnd(), hash.constEnd()));
+ Helper::checkCounter();
+
+ // non-const versions
+ QCOMPARE_EQ(hash[keyView], keys.size()); // already there
+ Helper::checkCounter();
+
+ QCOMPARE_EQ(hash[otherKeyView], 0); // inserts
+ Helper::resetCounter();
+ hash[otherKeyView] = INT_MAX;
+ Helper::checkCounter();
+
+ if constexpr (IsMultiHash) {
+ hash.insert(key, keys.size());
+ QCOMPARE_EQ(hash.count(keyView), 2);
+
+ // not depending on which of the two the current implementation finds
+ QCOMPARE_NE(hash.value(keyView), 0);
+ QCOMPARE_NE(hash.value(keyView, -1000), -1000);
+ QCOMPARE_NE(std::as_const(hash)[keyView], 0);
+ QCOMPARE_NE(hash.find(keyView), hash.end());
+ QCOMPARE_NE(std::as_const(hash).find(keyView), hash.constEnd());
+ QCOMPARE_NE(hash.constFind(keyView), hash.constEnd());
+ QCOMPARE_NE(hash.equal_range(keyView), std::make_pair(hash.end(), hash.end()));
+ QCOMPARE_NE(std::as_const(hash).equal_range(keyView),
+ std::make_pair(hash.constEnd(), hash.constEnd()));
+
+ // QMultiHash-specific functions
+ QVERIFY(hash.contains(keyView, keys.size()));
+ QCOMPARE_EQ(hash.count(keyView, 0), 0);
+ QCOMPARE_EQ(hash.count(keyView, keys.size()), 2);
+ QCOMPARE_EQ(hash.values(keyView), QList<qsizetype>({ keys.size(), keys.size() }));
+
+ hash.insert(key, -keys.size());
+ QCOMPARE_EQ(hash.count(keyView), 3);
+ QCOMPARE_EQ(hash.find(keyView, 0), hash.end());
+ QCOMPARE_NE(hash.find(keyView, keys.size()), hash.end());
+ QCOMPARE_NE(hash.find(keyView, -keys.size()), hash.end());
+ QCOMPARE_EQ(std::as_const(hash).find(keyView, 0), hash.constEnd());
+ QCOMPARE_NE(std::as_const(hash).find(keyView, keys.size()), hash.constEnd());
+ QCOMPARE_NE(std::as_const(hash).find(keyView, -keys.size()), hash.constEnd());
+ QCOMPARE_EQ(hash.constFind(keyView, 0), hash.constEnd());
+ QCOMPARE_NE(hash.constFind(keyView, keys.size()), hash.constEnd());
+ QCOMPARE_NE(hash.constFind(keyView, -keys.size()), hash.constEnd());
+
+ // removals
+ QCOMPARE_EQ(hash.remove(keyView, -keys.size()), 1);
+ QCOMPARE_EQ(hash.remove(keyView), 2);
+ } else {
+ // removals
+ QCOMPARE_EQ(hash.remove(keyView), true);
+ }
+
+ QCOMPARE_EQ(hash.take(otherKeyView), INT_MAX);
+ QVERIFY(hash.isEmpty());
+ Helper::checkCounter();
+
+ // repeat with more keys
+ for (qsizetype i = 0; i < keys.size() - 1; ++i) {
+ hash.insert(keys[i], -(i + 1));
+ hash.insert(keys[i], i + 1);
+ }
+
+ QVERIFY(!hash.contains(keyView));
+ QCOMPARE_EQ(hash.count(keyView), 0);
+ QCOMPARE_EQ(hash.value(keyView), 0);
+ QCOMPARE_EQ(hash.value(keyView, -1), -1);
+ QCOMPARE_EQ(std::as_const(hash)[keyView], 0);
+ QCOMPARE_EQ(hash.find(keyView), hash.end());
+ QCOMPARE_EQ(hash.constFind(keyView), hash.constEnd());
+ Helper::checkCounter();
+#else
+ Q_UNUSED(keys);
+ Q_UNUSED(conv);
+ QSKIP("This feature requires C++20 (concepts)");
+#endif
+}
+
+template <template <typename, typename> class Hash, typename String, typename View>
+static void heterogeneousSearchTest(const QList<std::remove_const_t<String>> &keys)
+{
+ heterogeneousSearchTest<Hash, String, View>(keys, [](const String &s) { return View(s); });
+}
+
+template <template <typename, typename> class Hash, typename T>
+static void heterogeneousSearchLatin1String(T)
+{
+ if constexpr (!T::value) {
+ QSKIP("QLatin1StringView and QString do not have the same hash on this platform");
+ } else {
+ // similar to the above
+ auto toLatin1 = [](const QString &s) { return s.toLatin1(); };
+ heterogeneousSearchTest<Hash, QString, QLatin1StringView>({ "Hello", {}, "World" }, toLatin1);
+ }
+}
+
+void tst_QHash::heterogeneousSearch()
+{
+ heterogeneousSearchTest<QHash, QString, HeterogeneousHashingType>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::heterogeneousSearchConstKey()
+{
+ // QHash<const QString, X> seen in the wild (e.g. Qt Creator)
+ heterogeneousSearchTest<QHash, const QString, HeterogeneousHashingType>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::heterogeneousSearchByteArray()
+{
+ heterogeneousSearchTest<QHash, QByteArray, QByteArrayView>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::heterogeneousSearchString()
+{
+ heterogeneousSearchTest<QHash, QString, QStringView>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::heterogeneousSearchLatin1String()
+{
+ ::heterogeneousSearchLatin1String<QHash>(QHashHeterogeneousSearch<QString, QLatin1StringView>{});
+}
+
void tst_QHash::compare()
{
QHash<int, QString> hash1,hash2;
QString testString = "Teststring %1";
int i;
- for(i = 0; i < 1000; ++i)
+ for (i = 0; i < 1000; ++i)
hash1.insert(i,testString.arg(i));
- for(--i; i >= 0; --i)
+ for (--i; i >= 0; --i)
hash2.insert(i,testString.arg(i));
hash1.squeeze();
@@ -947,39 +1415,39 @@ void tst_QHash::compare()
void tst_QHash::compare2()
{
- QHash<int, int> a;
- QHash<int, int> b;
+ QMultiHash<int, int> a;
+ QMultiHash<int, int> b;
- a.insertMulti(17, 1);
- a.insertMulti(17 * 2, 1);
- b.insertMulti(17 * 2, 1);
- b.insertMulti(17, 1);
+ a.insert(17, 1);
+ a.insert(17 * 2, 1);
+ b.insert(17 * 2, 1);
+ b.insert(17, 1);
QVERIFY(a == b);
QVERIFY(b == a);
- a.insertMulti(17, 2);
- a.insertMulti(17 * 2, 3);
- b.insertMulti(17 * 2, 3);
- b.insertMulti(17, 2);
+ a.insert(17, 2);
+ a.insert(17 * 2, 3);
+ b.insert(17 * 2, 3);
+ b.insert(17, 2);
QVERIFY(a == b);
QVERIFY(b == a);
- a.insertMulti(17, 4);
- a.insertMulti(17 * 2, 5);
- b.insertMulti(17 * 2, 4);
- b.insertMulti(17, 5);
+ a.insert(17, 4);
+ a.insert(17 * 2, 5);
+ b.insert(17 * 2, 4);
+ b.insert(17, 5);
QVERIFY(!(a == b));
QVERIFY(!(b == a));
a.clear();
b.clear();
- a.insertMulti(1, 1);
- a.insertMulti(1, 2);
- a.insertMulti(1, 3);
- b.insertMulti(1, 1);
- b.insertMulti(1, 2);
- b.insertMulti(1, 3);
- b.insertMulti(1, 4);
+ a.insert(1, 1);
+ a.insert(1, 2);
+ a.insert(1, 3);
+ b.insert(1, 1);
+ b.insert(1, 2);
+ b.insert(1, 3);
+ b.insert(1, 4);
QVERIFY(!(a == b));
QVERIFY(!(b == a));
}
@@ -993,7 +1461,7 @@ void tst_QHash::iterators()
QString testString1;
int i;
- for(i = 1; i < 100; ++i)
+ for (i = 1; i < 100; ++i)
hash.insert(i, testString.arg(i));
//to get some chaos in the hash
@@ -1010,18 +1478,13 @@ void tst_QHash::iterators()
QVERIFY(stlIt.value() == testMap.value(1));
- stlIt+=5;
+ for (int i = 0; i < 5; ++i)
+ ++stlIt;
QVERIFY(stlIt.value() == testMap.value(6));
stlIt++;
QVERIFY(stlIt.value() == testMap.value(7));
- stlIt-=3;
- QVERIFY(stlIt.value() == testMap.value(4));
-
- stlIt--;
- QVERIFY(stlIt.value() == testMap.value(3));
-
testMap.clear();
//STL-Style const-iterators
@@ -1035,18 +1498,13 @@ void tst_QHash::iterators()
QVERIFY(cstlIt.value() == testMap.value(1));
- cstlIt+=5;
+ for (int i = 0; i < 5; ++i)
+ ++cstlIt;
QVERIFY(cstlIt.value() == testMap.value(6));
cstlIt++;
QVERIFY(cstlIt.value() == testMap.value(7));
- cstlIt-=3;
- QVERIFY(cstlIt.value() == testMap.value(4));
-
- cstlIt--;
- QVERIFY(cstlIt.value() == testMap.value(3));
-
testMap.clear();
//Java-Style iterators
@@ -1068,14 +1526,7 @@ void tst_QHash::iterators()
QVERIFY(javaIt.value() == testMap.value(i));
}
- ++i;
- while(javaIt.hasPrevious()) {
- --i;
- javaIt.previous();
- QVERIFY(javaIt.value() == testMap.value(i));
- }
-
- //peekNext() peekPrevious()
+ //peekNext()
javaIt.toFront();
javaIt.next();
while(javaIt.hasNext()) {
@@ -1083,25 +1534,147 @@ void tst_QHash::iterators()
testString1 = javaIt.peekNext().value();
javaIt.next();
QVERIFY(javaIt.value() == testString1);
- QCOMPARE(javaIt.peekPrevious().value(), testString1);
}
- while(javaIt.hasPrevious()) {
- testString = javaIt.value();
- testString1 = javaIt.peekPrevious().value();
- javaIt.previous();
- QVERIFY(javaIt.value() == testString1);
- QCOMPARE(javaIt.peekNext().value(), testString1);
+}
+
+void tst_QHash::multihashIterators()
+{
+ QMultiHash<int, QString> hash;
+ QMap<int, QString> referenceMap;
+ QString testString = "Teststring %1-%2";
+ int i = 0;
+
+ // Add 5 elements for each key
+ for (i = 0; i < 10; ++i) {
+ for (int j = 0; j < 5; ++j)
+ hash.insert(i, testString.arg(i, j));
}
+
+ hash.squeeze();
+
+ // Verify that iteration is reproducible.
+
+ // STL iterator
+ QMultiHash<int, QString>::iterator stlIt;
+
+ for (stlIt = hash.begin(), i = 1; stlIt != hash.end(); ++stlIt, ++i)
+ referenceMap.insert(i, *stlIt);
+
+ stlIt = hash.begin();
+ QCOMPARE(*stlIt, referenceMap[1]);
+
+ for (i = 0; i < 5; ++i)
+ stlIt++;
+ QCOMPARE(*stlIt, referenceMap[6]);
+
+ for (i = 0; i < 44; ++i)
+ stlIt++;
+ QCOMPARE(*stlIt, referenceMap[50]);
+
+ // const STL iterator
+ referenceMap.clear();
+ QMultiHash<int, QString>::const_iterator cstlIt;
+
+ for (cstlIt = hash.cbegin(), i = 1; cstlIt != hash.cend(); ++cstlIt, ++i)
+ referenceMap.insert(i, *cstlIt);
+
+ cstlIt = hash.cbegin();
+ QCOMPARE(*cstlIt, referenceMap[1]);
+
+ for (i = 0; i < 5; ++i)
+ cstlIt++;
+ QCOMPARE(*cstlIt, referenceMap[6]);
+
+ for (i = 0; i < 44; ++i)
+ cstlIt++;
+ QCOMPARE(*cstlIt, referenceMap[50]);
+
+ // Java-Style iterator
+ referenceMap.clear();
+ QMultiHashIterator<int, QString> javaIt(hash);
+
+ // walk through
+ i = 0;
+ while (javaIt.hasNext()) {
+ ++i;
+ javaIt.next();
+ referenceMap.insert(i, javaIt.value());
+ }
+ javaIt.toFront();
+ i = 0;
+ while (javaIt.hasNext()) {
+ ++i;
+ javaIt.next();
+ QCOMPARE(javaIt.value(), referenceMap.value(i));
+ }
+
+ // peekNext()
+ javaIt.toFront();
+ javaIt.next();
+ QString nextValue;
+ while (javaIt.hasNext()) {
+ nextValue = javaIt.peekNext().value();
+ javaIt.next();
+ QCOMPARE(javaIt.value(), nextValue);
+ }
+}
+
+template<typename T>
+void iteratorsInEmptyHashTestMethod()
+{
+ T hash;
+ using ConstIter = typename T::const_iterator;
+ ConstIter it1 = hash.cbegin();
+ ConstIter it2 = hash.constBegin();
+ QVERIFY(it1 == it2 && it2 == ConstIter());
+ QVERIFY(!hash.isDetached());
+
+ ConstIter it3 = hash.cend();
+ ConstIter it4 = hash.constEnd();
+ QVERIFY(it3 == it4 && it4 == ConstIter());
+ QVERIFY(!hash.isDetached());
+
+ // to call const overloads of begin() and end()
+ const T hash2;
+ ConstIter it5 = hash2.begin();
+ ConstIter it6 = hash2.end();
+ QVERIFY(it5 == it6 && it6 == ConstIter());
+ QVERIFY(!hash2.isDetached());
+
+ T hash3;
+ using Iter = typename T::iterator;
+ Iter it7 = hash3.end();
+ QVERIFY(it7 == Iter());
+ QVERIFY(!hash3.isDetached());
+
+ Iter it8 = hash3.begin(); // calls detach()
+ QVERIFY(it8 == Iter());
+ QVERIFY(hash3.isDetached());
+}
+
+void tst_QHash::iteratorsInEmptyHash()
+{
+ iteratorsInEmptyHashTestMethod<QHash<int, QString>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ iteratorsInEmptyHashTestMethod<QMultiHash<int, QString>>();
}
void tst_QHash::keyIterator()
{
QHash<int, int> hash;
+ using KeyIterator = QHash<int, int>::key_iterator;
+ KeyIterator it1 = hash.keyBegin();
+ KeyIterator it2 = hash.keyEnd();
+ QVERIFY(it1 == it2 && it2 == KeyIterator());
+ QVERIFY(!hash.isDetached());
+
for (int i = 0; i < 100; ++i)
hash.insert(i, i*100);
- QHash<int, int>::key_iterator key_it = hash.keyBegin();
+ KeyIterator key_it = hash.keyBegin();
QHash<int, int>::const_iterator it = hash.cbegin();
for (int i = 0; i < 100; ++i) {
QCOMPARE(*key_it, it.key());
@@ -1115,15 +1688,55 @@ void tst_QHash::keyIterator()
QVERIFY(key_it != hash.keyEnd());
QCOMPARE(*key_it, it.key());
QCOMPARE(*(key_it++), (it++).key());
- QCOMPARE(*(key_it--), (it--).key());
- QCOMPARE(*(++key_it), (++it).key());
- QCOMPARE(*(--key_it), (--it).key());
+ if (key_it != hash.keyEnd()) {
+ QVERIFY(it != hash.cend());
+ ++key_it;
+ ++it;
+ if (key_it != hash.keyEnd())
+ QCOMPARE(*key_it, it.key());
+ else
+ QVERIFY(it == hash.cend());
+ }
QCOMPARE(std::count(hash.keyBegin(), hash.keyEnd(), 99), 1);
// DefaultConstructible test
- typedef QHash<int, int>::key_iterator keyIterator;
- Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value);
+ static_assert(std::is_default_constructible<KeyIterator>::value);
+}
+
+void tst_QHash::multihashKeyIterator()
+{
+ QMultiHash<int, int> hash;
+
+ using KeyIterator = QMultiHash<int, int>::key_iterator;
+ KeyIterator it1 = hash.keyBegin();
+ KeyIterator it2 = hash.keyEnd();
+ QVERIFY(it1 == it2 && it2 == KeyIterator());
+ QVERIFY(!hash.isDetached());
+
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 5; ++j)
+ hash.insert(i, i * 100 + j);
+ }
+
+ KeyIterator keyIt = hash.keyBegin();
+ QMultiHash<int, int>::const_iterator it = hash.cbegin();
+ while (keyIt != hash.keyEnd() && it != hash.cend()) {
+ QCOMPARE(*keyIt, it.key());
+ keyIt++;
+ it++;
+ }
+
+ keyIt = std::find(hash.keyBegin(), hash.keyEnd(), 5);
+ it = std::find(hash.cbegin(), hash.cend(), 5 * 100 + 2);
+
+ QVERIFY(keyIt != hash.keyEnd());
+ QCOMPARE(*keyIt, it.key());
+
+ QCOMPARE(std::count(hash.keyBegin(), hash.keyEnd(), 9), 5);
+
+ // DefaultConstructible test
+ static_assert(std::is_default_constructible<KeyIterator>::value);
}
void tst_QHash::keyValueIterator()
@@ -1144,6 +1757,12 @@ void tst_QHash::keyValueIterator()
entry_type pair(it.key(), it.value());
QCOMPARE(*key_value_it, pair);
+ QCOMPARE(key_value_it->first, pair.first);
+ QCOMPARE(key_value_it->second, pair.second);
+ QCOMPARE(&(*key_value_it).first, &it.key());
+ QCOMPARE(&key_value_it->first, &it.key());
+ QCOMPARE(&(*key_value_it).second, &it.value());
+ QCOMPARE(&key_value_it->second, &it.value());
++key_value_it;
++it;
}
@@ -1162,31 +1781,105 @@ void tst_QHash::keyValueIterator()
++it;
++key_value_it;
- QCOMPARE(*key_value_it, entry_type(it.key(), it.value()));
+ if (it != hash.cend())
+ QCOMPARE(*key_value_it, entry_type(it.key(), it.value()));
+ else
+ QVERIFY(key_value_it == hash.constKeyValueEnd());
- --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::multihashKeyValueIterator()
+{
+ QMultiHash<int, int> hash;
+ using EntryType = QHash<int, int>::const_key_value_iterator::value_type;
+
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 5; j++)
+ hash.insert(i, i * 100 + j);
+ }
+
+ auto keyValueIt = hash.constKeyValueBegin();
+ auto it = hash.cbegin();
+
+ for (int i = 0; i < hash.size(); ++i) {
+ QVERIFY(keyValueIt != hash.constKeyValueEnd());
+ QVERIFY(it != hash.cend());
+
+ EntryType pair(it.key(), it.value());
+ QCOMPARE(*keyValueIt, pair);
+ QCOMPARE(keyValueIt->first, pair.first);
+ QCOMPARE(keyValueIt->second, pair.second);
+ ++keyValueIt;
+ ++it;
+ }
+
+ QVERIFY(keyValueIt == hash.constKeyValueEnd());
+ QVERIFY(it == hash.cend());
+
+ int key = 5;
+ int value = key * 100 + 3;
+ EntryType pair(key, value);
+ keyValueIt = std::find(hash.constKeyValueBegin(), hash.constKeyValueEnd(), pair);
+ it = std::find(hash.cbegin(), hash.cend(), value);
+
+ QVERIFY(keyValueIt != hash.constKeyValueEnd());
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ key = 9;
+ value = key * 100 + 4;
+ const auto numItems =
+ std::count(hash.constKeyValueBegin(), hash.constKeyValueEnd(), EntryType(key, value));
+ QCOMPARE(numItems, 1);
+}
+
+template<typename T>
+void keyValueIteratorInEmptyHashTestMethod()
+{
+ T hash;
+ using ConstKeyValueIter = typename T::const_key_value_iterator;
+
+ ConstKeyValueIter it1 = hash.constKeyValueBegin();
+ ConstKeyValueIter it2 = hash.constKeyValueEnd();
+ QVERIFY(it1 == it2 && it2 == ConstKeyValueIter());
+ QVERIFY(!hash.isDetached());
+
+ const T hash2;
+ ConstKeyValueIter it3 = hash2.keyValueBegin();
+ ConstKeyValueIter it4 = hash2.keyValueEnd();
+ QVERIFY(it3 == it4 && it4 == ConstKeyValueIter());
+ QVERIFY(!hash.isDetached());
+
+ T hash3;
+ using KeyValueIter = typename T::key_value_iterator;
+
+ KeyValueIter it5 = hash3.keyValueEnd();
+ QVERIFY(it5 == KeyValueIter());
+ QVERIFY(!hash3.isDetached());
+
+ KeyValueIter it6 = hash3.keyValueBegin(); // calls detach()
+ QVERIFY(it6 == KeyValueIter());
+ QVERIFY(hash3.isDetached());
+}
+
+void tst_QHash::keyValueIteratorInEmptyHash()
+{
+ keyValueIteratorInEmptyHashTestMethod<QHash<int, int>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ keyValueIteratorInEmptyHashTestMethod<QMultiHash<int, int>>();
+}
+
void tst_QHash::rehash_isnt_quadratic()
{
// this test should be incredibly slow if rehash() is quadratic
for (int j = 0; j < 5; ++j) {
QHash<int, int> testHash;
for (int i = 0; i < 500000; ++i)
- testHash.insertMulti(1, 1);
+ testHash.insert(i, 1);
}
}
@@ -1218,16 +1911,24 @@ void tst_QHash::dont_need_default_constructor()
void tst_QHash::qmultihash_specific()
{
QMultiHash<int, int> hash1;
+
+ QVERIFY(!hash1.contains(1));
+ QVERIFY(!hash1.contains(1, 2));
+ QVERIFY(!hash1.isDetached());
+
for (int i = 1; i <= 9; ++i) {
+ QVERIFY(!hash1.contains(i));
for (int j = 1; j <= i; ++j) {
int k = i * 10 + j;
QVERIFY(!hash1.contains(i, k));
hash1.insert(i, k);
QVERIFY(hash1.contains(i, k));
}
+ QVERIFY(hash1.contains(i));
}
for (int i = 1; i <= 9; ++i) {
+ QVERIFY(hash1.contains(i));
for (int j = 1; j <= i; ++j) {
int k = i * 10 + j;
QVERIFY(hash1.contains(i, k));
@@ -1235,26 +1936,26 @@ void tst_QHash::qmultihash_specific()
}
QVERIFY(hash1.contains(9, 99));
- QCOMPARE(hash1.count(), 45);
+ QCOMPARE(hash1.size(), 45);
hash1.remove(9, 99);
QVERIFY(!hash1.contains(9, 99));
- QCOMPARE(hash1.count(), 44);
+ QCOMPARE(hash1.size(), 44);
hash1.remove(9, 99);
QVERIFY(!hash1.contains(9, 99));
- QCOMPARE(hash1.count(), 44);
+ QCOMPARE(hash1.size(), 44);
hash1.remove(1, 99);
- QCOMPARE(hash1.count(), 44);
+ QCOMPARE(hash1.size(), 44);
hash1.insert(1, 99);
hash1.insert(1, 99);
- QCOMPARE(hash1.count(), 46);
+ QCOMPARE(hash1.size(), 46);
hash1.remove(1, 99);
- QCOMPARE(hash1.count(), 44);
+ QCOMPARE(hash1.size(), 44);
hash1.remove(1, 99);
- QCOMPARE(hash1.count(), 44);
+ QCOMPARE(hash1.size(), 44);
{
QMultiHash<int, int>::const_iterator i = hash1.constFind(1, 11);
@@ -1299,6 +2000,12 @@ void tst_QHash::qmultihash_specific()
QVERIFY(i.value() == 98);
}
+ QCOMPARE(hash1.count(9), 8);
+ QCOMPARE(hash1.size(), 44);
+ hash1.remove(9);
+ QCOMPARE(hash1.count(9), 0);
+ QCOMPARE(hash1.size(), 36);
+
{
QMultiHash<int, int> map1;
map1.insert(42, 1);
@@ -1313,63 +2020,394 @@ void tst_QHash::qmultihash_specific()
map2.insert(42, 1);
map2.insert(10, 2);
map2.insert(48, 3);
- QCOMPARE(map1.count(), map2.count());
+ QCOMPARE(map1.size(), map2.size());
QVERIFY(map1.remove(42,5));
+ QVERIFY(map1 != map2);
QVERIFY(map2.remove(42,5));
QVERIFY(map1 == map2);
+
+ QHash<int, int> hash;
+ hash.insert(-1, -1);
+ map2.unite(hash);
+ QCOMPARE(map2.size(), 6);
+ QCOMPARE(map2[-1], -1);
}
}
-template <typename T>
-QList<T> sorted(const QList<T> &list)
+void tst_QHash::qmultihash_qhash_rvalue_ref_ctor()
{
- QList<T> res = list;
- std::sort(res.begin(), res.end());
- return res;
+ // QHash is empty
+ {
+ QHash<int, MyClass> hash;
+ QMultiHash<int, MyClass> multiHash(std::move(hash));
+ QVERIFY(multiHash.isEmpty());
+ }
+
+ // QHash is detached
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QHash<int, MyClass> hash;
+ hash.emplace(0, "a");
+ hash.emplace(1, "b");
+ QMultiHash<int, MyClass> multiHash(std::move(hash));
+ QCOMPARE(multiHash.size(), 2);
+ QCOMPARE(multiHash[0].str, QString("a"));
+ QCOMPARE(multiHash[1].str, QString("b"));
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 2);
+ QCOMPARE(MyClass::count, 2);
+ }
+
+ // QHash is shared
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QHash<int, MyClass> hash;
+ hash.emplace(0, "a");
+ hash.emplace(1, "b");
+ QHash<int, MyClass> hash2(hash);
+ QMultiHash<int, MyClass> multiHash(std::move(hash));
+ QCOMPARE(multiHash.size(), 2);
+ QCOMPARE(multiHash[0].str, QString("a"));
+ QCOMPARE(multiHash[1].str, QString("b"));
+ QCOMPARE(MyClass::copies, 2);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 4);
+ }
+}
+
+void tst_QHash::qmultihash_qhash_rvalue_ref_unite()
+{
+ // QHash is empty
+ {
+ QHash<int, MyClass> hash;
+ QMultiHash<int, MyClass> multiHash;
+ multiHash.unite(std::move(hash));
+ QVERIFY(multiHash.isEmpty());
+ }
+
+ // QHash is detached
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QHash<int, MyClass> hash;
+ hash.emplace(0, "a");
+ hash.emplace(1, "b");
+ QMultiHash<int, MyClass> multiHash;
+ multiHash.unite(std::move(hash));
+ QCOMPARE(multiHash.size(), 2);
+ QCOMPARE(multiHash[0].str, QString("a"));
+ QCOMPARE(multiHash[1].str, QString("b"));
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 2);
+ QCOMPARE(MyClass::count, 2);
+ }
+
+ // QHash is shared
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QHash<int, MyClass> hash;
+ hash.emplace(0, "a");
+ hash.emplace(1, "b");
+ QHash<int, MyClass> hash2(hash);
+ QMultiHash<int, MyClass> multiHash;
+ multiHash.unite(std::move(hash));
+ QCOMPARE(multiHash.size(), 2);
+ QCOMPARE(multiHash[0].str, QString("a"));
+ QCOMPARE(multiHash[1].str, QString("b"));
+ QCOMPARE(MyClass::copies, 2);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 4);
+ }
+
+ // QMultiHash already contains an item with the same key
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QHash<int, MyClass> hash;
+ hash.emplace(0, "a");
+ hash.emplace(1, "b");
+ QMultiHash<int, MyClass> multiHash;
+ multiHash.emplace(0, "c");
+ multiHash.unite(std::move(hash));
+ QCOMPARE(multiHash.size(), 3);
+ const auto aRange = multiHash.equal_range(0);
+ QCOMPARE(std::distance(aRange.first, aRange.second), 2);
+ auto it = aRange.first;
+ QCOMPARE(it->str, QString("a"));
+ QCOMPARE((++it)->str, QString("c"));
+ QCOMPARE(multiHash[1].str, QString("b"));
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 2);
+ QCOMPARE(MyClass::count, 3);
+ }
+}
+
+void tst_QHash::qmultihashUnite()
+{
+ // Joining two multi hashes, first is empty
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash2.emplace(0, "a");
+ hash2.emplace(1, "b");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+
+ hash1.unite(hash2);
+ // hash1 is empty, so we just share the data between hash1 and hash2
+ QCOMPARE(hash1.size(), 2);
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+ }
+ // Joining two multi hashes, second is empty
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash1.emplace(0, "a");
+ hash1.emplace(1, "b");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+
+ hash1.unite(hash2);
+ // hash2 is empty, so nothing happens
+ QVERIFY(hash2.isEmpty());
+ QVERIFY(!hash2.isDetached());
+ QCOMPARE(hash1.size(), 2);
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+ }
+ // Joining two multi hashes
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash1.emplace(0, "a");
+ hash1.emplace(1, "b");
+ hash2.emplace(0, "c");
+ hash2.emplace(1, "d");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 4);
+
+ hash1.unite(hash2);
+ QCOMPARE(hash1.size(), 4);
+ QCOMPARE(MyClass::copies, 2);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 6);
+ }
+
+ // operator+() uses unite() internally.
+
+ // using operator+(), hash1 is empty
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash2.emplace(0, "a");
+ hash2.emplace(1, "b");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+
+ auto hash3 = hash1 + hash2;
+ // hash1 is empty, so we just share the data between hash3 and hash2
+ QCOMPARE(hash1.size(), 0);
+ QCOMPARE(hash2.size(), 2);
+ QCOMPARE(hash3.size(), 2);
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+ }
+ // using operator+(), hash2 is empty
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash1.emplace(0, "a");
+ hash1.emplace(1, "b");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+
+ auto hash3 = hash1 + hash2;
+ // hash2 is empty, so we just share the data between hash3 and hash1
+ QCOMPARE(hash1.size(), 2);
+ QCOMPARE(hash2.size(), 0);
+ QCOMPARE(hash3.size(), 2);
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 2);
+ }
+ // using operator+()
+ {
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+ QMultiHash<int, MyClass> hash1;
+ QMultiHash<int, MyClass> hash2;
+ hash1.emplace(0, "a");
+ hash1.emplace(1, "b");
+ hash2.emplace(0, "c");
+ hash2.emplace(1, "d");
+
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 4);
+
+ auto hash3 = hash1 + hash2;
+ QCOMPARE(hash1.size(), 2);
+ QCOMPARE(hash2.size(), 2);
+ QCOMPARE(hash3.size(), 4);
+ QCOMPARE(MyClass::copies, 4);
+ QCOMPARE(MyClass::moves, 0);
+ QCOMPARE(MyClass::count, 8);
+ }
+}
+
+void tst_QHash::qmultihashSize()
+{
+ // QMultiHash has an extra m_size member that counts the number of values,
+ // while d->size (shared with QHash) counts the number of distinct keys.
+ {
+ QMultiHash<int, int> hash;
+ QCOMPARE(hash.size(), 0);
+ QVERIFY(hash.isEmpty());
+
+ hash.insert(0, 42);
+ QCOMPARE(hash.size(), 1);
+ QVERIFY(!hash.isEmpty());
+
+ hash.insert(0, 42);
+ QCOMPARE(hash.size(), 2);
+ QVERIFY(!hash.isEmpty());
+
+ hash.emplace(0, 42);
+ QCOMPARE(hash.size(), 3);
+ QVERIFY(!hash.isEmpty());
+
+ QCOMPARE(hash.take(0), 42);
+ QCOMPARE(hash.size(), 2);
+ QVERIFY(!hash.isEmpty());
+
+ QCOMPARE(hash.remove(0), 2);
+ QCOMPARE(hash.size(), 0);
+ QVERIFY(hash.isEmpty());
+ }
+
+ {
+ QMultiHash<int, int> hash;
+ hash.emplace(0, 0);
+ hash.emplace(0, 0);
+ QCOMPARE(hash.size(), 2);
+ QVERIFY(!hash.isEmpty());
+
+ hash.emplace(0, 1);
+ QCOMPARE(hash.size(), 3);
+ QVERIFY(!hash.isEmpty());
+
+ QCOMPARE(hash.remove(0, 0), 2);
+ QCOMPARE(hash.size(), 1);
+ QVERIFY(!hash.isEmpty());
+
+ hash.remove(0);
+ QCOMPARE(hash.size(), 0);
+ QVERIFY(hash.isEmpty());
+ }
+
+ {
+ QMultiHash<int, int> hash;
+
+ hash[0] = 0;
+ QCOMPARE(hash.size(), 1);
+ QVERIFY(!hash.isEmpty());
+
+ hash.replace(0, 1);
+ QCOMPARE(hash.size(), 1);
+ QVERIFY(!hash.isEmpty());
+
+ hash.insert(0, 1);
+ hash.erase(hash.cbegin());
+ QCOMPARE(hash.size(), 1);
+ QVERIFY(!hash.isEmpty());
+
+ hash.erase(hash.cbegin());
+ QCOMPARE(hash.size(), 0);
+ QVERIFY(hash.isEmpty());
+ }
+}
+
+void tst_QHash::qmultihashHeterogeneousSearch()
+{
+ heterogeneousSearchTest<QMultiHash, QString, HeterogeneousHashingType>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::qmultihashHeterogeneousSearchConstKey()
+{
+ heterogeneousSearchTest<QMultiHash, const QString, HeterogeneousHashingType>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::qmultihashHeterogeneousSearchByteArray()
+{
+ heterogeneousSearchTest<QMultiHash, QByteArray, QByteArrayView>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::qmultihashHeterogeneousSearchString()
+{
+ heterogeneousSearchTest<QMultiHash, QString, QStringView>({ "Hello", {}, "World" });
+}
+
+void tst_QHash::qmultihashHeterogeneousSearchLatin1String()
+{
+ ::heterogeneousSearchLatin1String<QMultiHash>(QHashHeterogeneousSearch<QString, QLatin1StringView>{});
}
void tst_QHash::keys_values_uniqueKeys()
{
- QHash<QString, int> hash;
+ QMultiHash<QString, int> hash;
QVERIFY(hash.uniqueKeys().isEmpty());
QVERIFY(hash.keys().isEmpty());
QVERIFY(hash.values().isEmpty());
+ QVERIFY(!hash.isDetached());
- hash.insertMulti("alpha", 1);
+ hash.insert("alpha", 1);
QVERIFY(sorted(hash.keys()) == (QList<QString>() << "alpha"));
QVERIFY(hash.keys() == hash.uniqueKeys());
QVERIFY(hash.values() == (QList<int>() << 1));
- hash.insertMulti("beta", -2);
+ hash.insert("beta", -2);
QVERIFY(sorted(hash.keys()) == (QList<QString>() << "alpha" << "beta"));
QVERIFY(hash.keys() == hash.uniqueKeys());
QVERIFY(sorted(hash.values()) == sorted(QList<int>() << 1 << -2));
- hash.insertMulti("alpha", 2);
+ hash.insert("alpha", 2);
QVERIFY(sorted(hash.uniqueKeys()) == (QList<QString>() << "alpha" << "beta"));
QVERIFY(sorted(hash.keys()) == (QList<QString>() << "alpha" << "alpha" << "beta"));
QVERIFY(sorted(hash.values()) == sorted(QList<int>() << 2 << 1 << -2));
- hash.insertMulti("beta", 4);
+ hash.insert("beta", 4);
QVERIFY(sorted(hash.uniqueKeys()) == (QList<QString>() << "alpha" << "beta"));
QVERIFY(sorted(hash.keys()) == (QList<QString>() << "alpha" << "alpha" << "beta" << "beta"));
QVERIFY(sorted(hash.values()) == sorted(QList<int>() << 2 << 1 << 4 << -2));
}
-void tst_QHash::noNeedlessRehashes()
-{
- QHash<int, int> hash;
- for (int i = 0; i < 512; ++i) {
- int j = (i * 345) % 512;
- hash.insert(j, j);
- int oldCapacity = hash.capacity();
- hash[j] = j + 1;
- QCOMPARE(oldCapacity, hash.capacity());
- hash.insert(j, j + 1);
- QCOMPARE(oldCapacity, hash.capacity());
- }
-}
-
void tst_QHash::const_shared_null()
{
QHash<int, QString> hash2;
@@ -1381,52 +2419,52 @@ static int wrongqHashOverload = 0;
struct OneArgumentQHashStruct1 {};
bool operator==(const OneArgumentQHashStruct1 &, const OneArgumentQHashStruct1 &) { return false; }
-uint qHash(OneArgumentQHashStruct1) { return 0; }
+size_t qHash(OneArgumentQHashStruct1) { return 0; }
struct OneArgumentQHashStruct2 {};
bool operator==(const OneArgumentQHashStruct2 &, const OneArgumentQHashStruct2 &) { return false; }
-uint qHash(const OneArgumentQHashStruct2 &) { return 0; }
+size_t qHash(const OneArgumentQHashStruct2 &) { return 0; }
struct OneArgumentQHashStruct3 {};
bool operator==(const OneArgumentQHashStruct3 &, const OneArgumentQHashStruct3 &) { return false; }
-uint qHash(OneArgumentQHashStruct3) { return 0; }
-uint qHash(OneArgumentQHashStruct3 &, uint) { wrongqHashOverload = 1; return 0; }
+size_t qHash(OneArgumentQHashStruct3) { return 0; }
+size_t qHash(OneArgumentQHashStruct3 &, size_t) { wrongqHashOverload = 1; return 0; }
struct OneArgumentQHashStruct4 {};
bool operator==(const OneArgumentQHashStruct4 &, const OneArgumentQHashStruct4 &) { return false; }
-uint qHash(const OneArgumentQHashStruct4 &) { return 0; }
-uint qHash(OneArgumentQHashStruct4 &, uint) { wrongqHashOverload = 1; return 0; }
+size_t qHash(const OneArgumentQHashStruct4 &) { return 0; }
+size_t qHash(OneArgumentQHashStruct4 &, size_t) { wrongqHashOverload = 1; return 0; }
struct TwoArgumentsQHashStruct1 {};
bool operator==(const TwoArgumentsQHashStruct1 &, const TwoArgumentsQHashStruct1 &) { return false; }
-uint qHash(const TwoArgumentsQHashStruct1 &) { wrongqHashOverload = 1; return 0; }
-uint qHash(const TwoArgumentsQHashStruct1 &, uint) { return 0; }
+size_t qHash(const TwoArgumentsQHashStruct1 &) { wrongqHashOverload = 1; return 0; }
+size_t qHash(const TwoArgumentsQHashStruct1 &, size_t) { return 0; }
struct TwoArgumentsQHashStruct2 {};
bool operator==(const TwoArgumentsQHashStruct2 &, const TwoArgumentsQHashStruct2 &) { return false; }
-uint qHash(TwoArgumentsQHashStruct2) { wrongqHashOverload = 1; return 0; }
-uint qHash(const TwoArgumentsQHashStruct2 &, uint) { return 0; }
+size_t qHash(TwoArgumentsQHashStruct2) { wrongqHashOverload = 1; return 0; }
+size_t qHash(const TwoArgumentsQHashStruct2 &, size_t) { return 0; }
struct TwoArgumentsQHashStruct3 {};
bool operator==(const TwoArgumentsQHashStruct3 &, const TwoArgumentsQHashStruct3 &) { return false; }
-uint qHash(const TwoArgumentsQHashStruct3 &) { wrongqHashOverload = 1; return 0; }
-uint qHash(TwoArgumentsQHashStruct3, uint) { return 0; }
+size_t qHash(const TwoArgumentsQHashStruct3 &) { wrongqHashOverload = 1; return 0; }
+size_t qHash(TwoArgumentsQHashStruct3, size_t) { return 0; }
struct TwoArgumentsQHashStruct4 {};
bool operator==(const TwoArgumentsQHashStruct4 &, const TwoArgumentsQHashStruct4 &) { return false; }
-uint qHash(TwoArgumentsQHashStruct4) { wrongqHashOverload = 1; return 0; }
-uint qHash(TwoArgumentsQHashStruct4, uint) { return 0; }
+size_t qHash(TwoArgumentsQHashStruct4) { wrongqHashOverload = 1; return 0; }
+size_t qHash(TwoArgumentsQHashStruct4, size_t) { return 0; }
/*!
\internal
Check that QHash picks up the right overload.
The best one, for a type T, is the two-args version of qHash:
- either uint qHash(T, uint) or uint qHash(const T &, uint).
+ either size_t qHash(T, size_t) or size_t qHash(const T &, size_t).
If neither of these exists, then one between
- uint qHash(T) or uint qHash(const T &) must exist
+ size_t qHash(T) or size_t qHash(const T &) must exist
(and it gets selected instead).
*/
void tst_QHash::twoArguments_qHash()
@@ -1475,7 +2513,7 @@ void tst_QHash::twoArguments_qHash()
void tst_QHash::initializerList()
{
QHash<int, QString> hash = {{1, "bar"}, {1, "hello"}, {2, "initializer_list"}};
- QCOMPARE(hash.count(), 2);
+ QCOMPARE(hash.size(), 2);
QCOMPARE(hash[1], QString("hello"));
QCOMPARE(hash[2], QString("initializer_list"));
@@ -1485,9 +2523,9 @@ void tst_QHash::initializerList()
// QCOMPARE(stdh[1], QString("bar"));
QMultiHash<QString, int> multiHash{{"il", 1}, {"il", 2}, {"il", 3}};
- QCOMPARE(multiHash.count(), 3);
+ QCOMPARE(multiHash.size(), 3);
QList<int> values = multiHash.values("il");
- QCOMPARE(values.count(), 3);
+ QCOMPARE(values.size(), 3);
QHash<int, int> emptyHash{};
QVERIFY(emptyHash.isEmpty());
@@ -1504,14 +2542,14 @@ void tst_QHash::initializerList()
void tst_QHash::eraseValidIteratorOnSharedHash()
{
- QHash<int, int> a, b;
+ QMultiHash<int, int> a, b;
a.insert(10, 10);
- a.insertMulti(10, 25);
- a.insertMulti(10, 30);
+ a.insert(10, 25);
+ a.insert(10, 30);
a.insert(20, 20);
a.insert(40, 40);
- QHash<int, int>::iterator i = a.begin();
+ auto i = a.begin();
while (i.value() != 25)
++i;
@@ -1533,7 +2571,7 @@ void tst_QHash::eraseValidIteratorOnSharedHash()
void tst_QHash::equal_range()
{
- QHash<int, QString> hash;
+ QMultiHash<int, QString> hash;
auto result = hash.equal_range(0);
QCOMPARE(result.first, hash.end());
@@ -1546,7 +2584,7 @@ void tst_QHash::equal_range()
QCOMPARE(result.first, hash.find(1));
QVERIFY(std::distance(result.first, result.second) == 1);
- QHash<int, int> h1;
+ QMultiHash<int, int> h1;
{
auto p = h1.equal_range(0);
QVERIFY(p.first == p.second);
@@ -1597,7 +2635,7 @@ void tst_QHash::equal_range()
QVERIFY(p2.first == m1.begin() || p2.second == m1.end());
}
- const QHash<int, int> ch1 = h1;
+ const QMultiHash<int, int> ch1 = h1;
{
auto p1 = ch1.equal_range(9);
QVERIFY(p1.first == p1.second);
@@ -1623,10 +2661,17 @@ void tst_QHash::equal_range()
QVERIFY(p2.first == cm1.cbegin() || p2.second == cm1.cend());
}
- QHash<int, int> h2;
+ {
+ const QMultiHash<int, int> cm2;
+ auto p1 = cm2.equal_range(0);
+ QVERIFY(p1.first == cm2.end());
+ QVERIFY(p1.second == cm2.end());
+ }
+
+ QMultiHash<int, int> h2;
for (int i = 0; i < 8; ++i)
for (int j = 0; j < 8; ++j)
- h2.insertMulti(i, i*j);
+ h2.insert(i, i*j);
for (int i = 0; i < 8; ++i) {
auto pair = h2.equal_range(i);
@@ -1652,7 +2697,7 @@ void tst_QHash::insert_hash()
hash.insert(hash2);
- QCOMPARE(hash.count(), 5);
+ QCOMPARE(hash.size(), 5);
for (int i = 0; i < 5; ++i)
QCOMPARE(hash[i], i);
}
@@ -1664,7 +2709,7 @@ void tst_QHash::insert_hash()
hash.insert(hash2);
- QCOMPARE(hash.count(), 1);
+ QCOMPARE(hash.size(), 1);
QCOMPARE(hash[0], 5);
}
{
@@ -1674,7 +2719,7 @@ void tst_QHash::insert_hash()
hash.insert(hash2);
- QCOMPARE(hash.count(), 1);
+ QCOMPARE(hash.size(), 1);
QCOMPARE(hash[0], 5);
QCOMPARE(hash, hash2);
}
@@ -1687,25 +2732,508 @@ void tst_QHash::insert_hash()
// insert into ourself, nothing should happen
hash.insert(hash);
- QCOMPARE(hash.count(), 3);
+ QCOMPARE(hash.size(), 3);
QCOMPARE(hash[0], 7);
QCOMPARE(hash[2], 5);
QCOMPARE(hash[7], 55);
}
+}
+
+void tst_QHash::multiHashStoresInReverseInsertionOrder()
+{
+ const QString strings[] = {
+ u"zero"_s,
+ u"null"_s,
+ u"nada"_s,
+ };
+ {
+ QMultiHash<int, QString> hash;
+ for (const QString &string : strings)
+ hash.insert(0, string);
+ auto printOnFailure = qScopeGuard([&] { qDebug() << hash; });
+ QVERIFY(std::equal(hash.begin(), hash.end(),
+ std::rbegin(strings), std::rend(strings)));
+ printOnFailure.dismiss();
+ }
+}
+
+void tst_QHash::emplace()
+{
+ {
+ QHash<QString, MyClass> hash;
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+
+ hash.emplace(QString("a"), QString("a"));
+ QCOMPARE(hash["a"].str, "a");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ hash.emplace(QString("ab"), QString("ab"));
+ QCOMPARE(hash["ab"].str, "ab");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ hash.emplace(QString("ab"), QString("abc"));
+ QCOMPARE(hash["ab"].str, "abc");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 1);
+ }
+ {
+ QMultiHash<QString, MyClass> hash;
+ MyClass::copies = 0;
+ MyClass::moves = 0;
+
+ hash.emplace(QString("a"), QString("a"));
+ QCOMPARE(hash["a"].str, "a");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ hash.emplace(QString("ab"), QString("ab"));
+ QCOMPARE(hash["ab"].str, "ab");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ hash.emplace(QString("ab"), QString("abc"));
+ QCOMPARE(hash["ab"].str, "abc");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 0);
+ hash.emplaceReplace(QString("ab"), QString("abcd"));
+ QCOMPARE(hash["ab"].str, "abcd");
+ QCOMPARE(MyClass::copies, 0);
+ QCOMPARE(MyClass::moves, 1);
+ }
+}
+
+struct BadKey {
+ int k;
+ BadKey(int i) : k(i) {}
+ bool operator==(const BadKey &other) const
+ {
+ return k == other.k;
+ }
+};
+
+size_t qHash(BadKey, size_t seed)
+{
+ return seed;
+}
+
+void tst_QHash::badHashFunction()
+{
+ QHash<BadKey, int> hash;
+ for (int i = 0; i < 10000; ++i)
+ hash.insert(i, i);
+
+ for (int i = 0; i < 10000; ++i)
+ QCOMPARE(hash.value(i), i);
+
+ for (int i = 10000; i < 20000; ++i)
+ QVERIFY(!hash.contains(i));
+
+}
+
+void tst_QHash::hashOfHash()
+{
+ QHash<int, int> hash;
+ (void)qHash(hash);
+
+ QMultiHash<int, int> multiHash;
+ (void)qHash(multiHash);
+}
+
+template <bool HasQHash_>
+struct StdHashKeyType {
+ static inline constexpr bool HasQHash = HasQHash_;
+ static bool StdHashUsed;
+
+ int i;
+ friend bool operator==(const StdHashKeyType &lhs, const StdHashKeyType &rhs)
+ { return lhs.i == rhs.i; }
+};
+
+template <bool HasQHash>
+bool StdHashKeyType<HasQHash>::StdHashUsed = false;
+
+namespace std {
+template <bool HasQHash> struct hash<StdHashKeyType<HasQHash>>
+{
+ size_t operator()(const StdHashKeyType<HasQHash> &s, size_t seed = 0) const {
+ StdHashKeyType<HasQHash>::StdHashUsed = true;
+ return hash<int>()(s.i) ^ seed;
+ }
+};
+}
+
+template <bool HasQHash>
+std::enable_if_t<HasQHash, size_t>
+qHash(const StdHashKeyType<HasQHash> &s, size_t seed)
+{
+ return qHash(s.i, seed);
+}
+
+template <typename T>
+void stdHashImpl()
+{
+ QHash<T, int> hash;
+ for (int i = 0; i < 1000; ++i)
+ hash.insert(T{i}, i);
+
+ QCOMPARE(hash.size(), 1000);
+ for (int i = 0; i < 1000; ++i)
+ QCOMPARE(hash.value(T{i}, -1), i);
+
+ for (int i = 500; i < 1500; ++i)
+ hash.insert(T{i}, i);
+
+ QCOMPARE(hash.size(), 1500);
+ for (int i = 0; i < 1500; ++i)
+ QCOMPARE(hash.value(T{i}, -1), i);
+
+ qsizetype count = 0;
+ for (int i = -2000; i < 2000; ++i) {
+ if (hash.contains(T{i}))
+ ++count;
+ }
+ QCOMPARE(count, 1500);
+ QCOMPARE(T::StdHashUsed, !T::HasQHash);
+
+
+ std::unordered_set<T> set;
+ for (int i = 0; i < 1000; ++i)
+ set.insert(T{i});
+
+ for (int i = 500; i < 1500; ++i)
+ set.insert(T{i});
+
+ QCOMPARE(set.size(), size_t(1500));
+ count = 0;
+ for (int i = -2000; i < 2000; ++i)
+ count += qsizetype(set.count(T{i}));
+ QCOMPARE(count, 1500);
+ QVERIFY(T::StdHashUsed);
+}
+
+void tst_QHash::stdHash()
+{
+ stdHashImpl<StdHashKeyType<false>>();
+ stdHashImpl<StdHashKeyType<true>>();
+
+ QSet<std::string> strings{ "a", "b", "c" };
+ QVERIFY(strings.contains("a"));
+ QVERIFY(!strings.contains("z"));
+}
+
+void tst_QHash::countInEmptyHash()
+{
{
- // This will use a QMultiHash and then insert that into QHash,
- // the ordering is undefined so we won't test that but make
- // sure this isn't adding multiple entries with the same key
- // to the QHash.
QHash<int, int> hash;
- QMultiHash<int, int> hash2;
- hash2.insert(0, 5);
- hash2.insert(0, 6);
- hash2.insert(0, 7);
+ QCOMPARE(hash.size(), 0);
+ QCOMPARE(hash.count(42), 0);
+ }
- hash.insert(hash2);
+ {
+ QMultiHash<int, int> hash;
+ QCOMPARE(hash.size(), 0);
+ QCOMPARE(hash.count(42), 0);
+ QCOMPARE(hash.count(42, 1), 0);
+ }
+}
+
+void tst_QHash::removeInEmptyHash()
+{
+ {
+ QHash<QString, int> hash;
+ QCOMPARE(hash.remove("test"), false);
+ QVERIFY(!hash.isDetached());
+
+ using Iter = QHash<QString, int>::iterator;
+ const auto removed = hash.removeIf([](Iter) { return true; });
+ QCOMPARE(removed, 0);
+ }
+ {
+ QMultiHash<QString, int> hash;
+ QCOMPARE(hash.remove("key"), 0);
+ QCOMPARE(hash.remove("key", 1), 0);
+ QVERIFY(!hash.isDetached());
+
+ using Iter = QMultiHash<QString, int>::iterator;
+ const auto removed = hash.removeIf([](Iter) { return true; });
+ QCOMPARE(removed, 0);
+ }
+}
+
+template<typename T>
+void valueInEmptyHashTestFunction()
+{
+ T hash;
+ QCOMPARE(hash.value("key"), 0);
+ QCOMPARE(hash.value("key", -1), -1);
+ QVERIFY(hash.values().isEmpty());
+ QVERIFY(!hash.isDetached());
+
+ const T constHash;
+ QCOMPARE(constHash["key"], 0);
+}
+
+void tst_QHash::valueInEmptyHash()
+{
+ valueInEmptyHashTestFunction<QHash<QString, int>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ valueInEmptyHashTestFunction<QMultiHash<QString, int>>();
+}
+
+void tst_QHash::fineTuningInEmptyHash()
+{
+ QHash<QString, int> hash;
+ QCOMPARE(hash.capacity(), 0);
+ hash.squeeze();
+ QCOMPARE(hash.capacity(), 0);
+ QVERIFY(qFuzzyIsNull(hash.load_factor()));
+ QVERIFY(!hash.isDetached());
+
+ hash.reserve(10);
+ QVERIFY(hash.capacity() >= 10);
+ hash.squeeze();
+ QVERIFY(hash.capacity() > 0);
+}
+
+void tst_QHash::reserveShared()
+{
+ QHash<char, char> hash;
+ hash.insert('c', 'c');
+ auto hash2 = hash;
+
+ QCOMPARE(hash2.capacity(), hash.capacity());
+ auto oldCap = hash.capacity();
+
+ hash2.reserve(100); // This shouldn't crash
+
+ QVERIFY(hash2.capacity() >= 100);
+ QCOMPARE(hash.capacity(), oldCap);
+}
+
+void tst_QHash::reserveLessThanCurrentAmount()
+{
+ {
+ QHash<int, int> hash;
+ for (int i = 0; i < 1000; ++i)
+ hash.insert(i, i * 10);
+
+ // This used to hang in an infinite loop: QTBUG-102067
+ hash.reserve(1);
+
+ // Make sure that hash still has all elements
+ for (int i = 0; i < 1000; ++i)
+ QCOMPARE(hash.value(i), i * 10);
+ }
+ {
+ QMultiHash<int, int> hash;
+ for (int i = 0; i < 1000; ++i) {
+ hash.insert(i, i * 10);
+ hash.insert(i, i * 10 + 1);
+ }
+
+ // This used to hang in infinite loop: QTBUG-102067
+ hash.reserve(1);
+
+ // Make sure that hash still has all elements
+ for (int i = 0; i < 1000; ++i)
+ QCOMPARE(hash.values(i), QList<int>({ i * 10 + 1, i * 10 }));
+ }
+}
+
+void tst_QHash::reserveKeepCapacity_data()
+{
+ QTest::addColumn<qsizetype>("requested");
+ auto addRow = [](qsizetype requested) {
+ QTest::addRow("%td", ptrdiff_t(requested)) << requested;
+ };
+
+ QHash<int, int> testHash = {{1, 1}};
+ qsizetype minCapacity = testHash.capacity();
+ addRow(minCapacity - 1);
+ addRow(minCapacity + 0);
+ addRow(minCapacity + 1);
+ addRow(2 * minCapacity - 1);
+ addRow(2 * minCapacity + 0);
+ addRow(2 * minCapacity + 1);
+}
+
+void tst_QHash::reserveKeepCapacity()
+{
+ QFETCH(qsizetype, requested);
+
+ QHash<qsizetype, qsizetype> hash;
+ hash.reserve(requested);
+ qsizetype initialCapacity = hash.capacity();
+ QCOMPARE_GE(initialCapacity, requested);
+
+ // insert this many elements into the hash
+ for (qsizetype i = 0; i < requested; ++i)
+ hash.insert(i, i);
+
+ // it mustn't have increased capacity after inserting the elements
+ QCOMPARE(hash.capacity(), initialCapacity);
+}
+
+void tst_QHash::QTBUG98265()
+{
+ QMultiHash<QUuid, QByteArray> a;
+ QMultiHash<QUuid, QByteArray> b;
+ a.insert(QUuid("3e0dfb4d-90eb-43a4-bd54-88f5b69832c1"), QByteArray());
+ b.insert(QUuid("1b710ada-3dd7-432e-b7c8-e852e59f46a0"), QByteArray());
+
+ QVERIFY(a != b);
+}
+
+/*
+ Calling functions which take a const-ref argument for a key with a reference
+ to a key inside the hash itself should keep the key valid as long as it is
+ needed. If not users may get hard-to-debug races where CoW should've
+ shielded them.
+*/
+void tst_QHash::detachAndReferences()
+{
+ // Repeat a few times because it's not a guarantee
+ for (int i = 0; i < 50; ++i) {
+ QHash<char, char> hash;
+ hash.insert('a', 'a');
+ hash.insert('b', 'a');
+ hash.insert('c', 'a');
+ hash.insert('d', 'a');
+ hash.insert('e', 'a');
+ hash.insert('f', 'a');
+ hash.insert('g', 'a');
+
+ QSemaphore sem;
+ QSemaphore sem2;
+ std::thread th([&sem, &sem2, hash]() mutable {
+ sem.release();
+ sem2.acquire();
+ hash.reserve(100); // [2]: ...then this rehashes directly, without detaching
+ });
+
+ // The key is a reference to an entry in the hash. If we were already
+ // detached then no problem occurs! The problem happens because _after_
+ // we detach but before using the key the other thread resizes and
+ // rehashes, leaving our const-ref dangling.
+ auto it = hash.constBegin();
+ const auto &key = it.key(); // [3]: leaving our const-refs dangling
+ auto kCopy = key;
+ const auto &value = it.value();
+ auto vCopy = value;
+ sem2.release();
+ sem.acquire();
+ hash.insert(key, value); // [1]: this detaches first...
+
+ th.join();
+ QCOMPARE(hash.size(), 7);
+ QVERIFY(hash.contains(kCopy));
+ QCOMPARE(hash.value(kCopy), vCopy);
+ }
+}
+
+void tst_QHash::lookupUsingKeyIterator()
+{
+ QHash<QString, QString> hash;
+ hash.reserve(1);
+ qsizetype minCapacity = hash.capacity();
+ // Beholden to internal implementation details:
+ qsizetype rehashLimit = minCapacity == 64 ? 63 : 8;
+
+ for (char16_t c = u'a'; c <= u'a' + rehashLimit; ++c)
+ hash.insert(QString(QChar(c)), u"h"_s);
+
+ for (auto it = hash.keyBegin(), end = hash.keyEnd(); it != end; ++it)
+ QVERIFY(!hash[*it].isEmpty());
+}
+
+void tst_QHash::squeeze()
+{
+ {
+ QHash<int, int> hash;
+ hash.reserve(1000);
+ for (int i = 0; i < 10; ++i)
+ hash.insert(i, i * 10);
+ QVERIFY(hash.isDetached());
+ const size_t buckets = hash.bucket_count();
+ const qsizetype size = hash.size();
+
+ hash.squeeze();
+
+ QVERIFY(hash.bucket_count() < buckets);
+ QCOMPARE(hash.size(), size);
+ for (int i = 0; i < size; ++i)
+ QCOMPARE(hash.value(i), i * 10);
+ }
+ {
+ QMultiHash<int, int> hash;
+ hash.reserve(1000);
+ for (int i = 0; i < 10; ++i) {
+ hash.insert(i, i * 10);
+ hash.insert(i, i * 10 + 1);
+ }
+ QVERIFY(hash.isDetached());
+ const size_t buckets = hash.bucket_count();
+ const qsizetype size = hash.size();
+
+ hash.squeeze();
+
+ QVERIFY(hash.bucket_count() < buckets);
+ QCOMPARE(hash.size(), size);
+ for (int i = 0; i < (size / 2); ++i)
+ QCOMPARE(hash.values(i), QList<int>({ i * 10 + 1, i * 10 }));
+ }
+}
+
+void tst_QHash::squeezeShared()
+{
+ {
+ QHash<int, int> hash;
+ hash.reserve(1000);
+ for (int i = 0; i < 10; ++i)
+ hash.insert(i, i * 10);
+
+ QHash<int, int> other = hash;
+
+ // Check that when squeezing a hash with shared d_ptr, the number of
+ // buckets actually decreases.
+ QVERIFY(!other.isDetached());
+ const size_t buckets = other.bucket_count();
+ const qsizetype size = other.size();
+
+ other.squeeze();
+
+ QCOMPARE(hash.bucket_count(), buckets);
+ QVERIFY(other.bucket_count() < buckets);
+
+ QCOMPARE(other.size(), size);
+ for (int i = 0; i < size; ++i)
+ QCOMPARE(other.value(i), i * 10);
+ }
+ {
+ QMultiHash<int, int> hash;
+ hash.reserve(1000);
+ for (int i = 0; i < 10; ++i) {
+ hash.insert(i, i * 10);
+ hash.insert(i, i * 10 + 1);
+ }
+
+ QMultiHash<int, int> other = hash;
+
+ // Check that when squeezing a hash with shared d_ptr, the number of
+ // buckets actually decreases.
+ QVERIFY(!other.isDetached());
+ const size_t buckets = other.bucket_count();
+ const qsizetype size = other.size();
+
+ other.squeeze();
+
+ QCOMPARE(hash.bucket_count(), buckets);
+ QVERIFY(other.bucket_count() < buckets);
- QCOMPARE(hash.count(), 1);
+ QCOMPARE(other.size(), size);
+ for (int i = 0; i < (size / 2); ++i)
+ QCOMPARE(other.values(i), QList<int>({ i * 10 + 1, i * 10 }));
}
}
diff --git a/tests/auto/corelib/tools/qhashfunctions/CMakeLists.txt b/tests/auto/corelib/tools/qhashfunctions/CMakeLists.txt
new file mode 100644
index 0000000000..6cbba503dc
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashfunctions/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qhashfunctions Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qhashfunctions LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qhashfunctions
+ SOURCES
+ tst_qhashfunctions.cpp
+)
diff --git a/tests/auto/corelib/tools/qhashfunctions/qhashfunctions.pro b/tests/auto/corelib/tools/qhashfunctions/qhashfunctions.pro
deleted file mode 100644
index 853e9f30e5..0000000000
--- a/tests/auto/corelib/tools/qhashfunctions/qhashfunctions.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qhashfunctions
-QT = core testlib
-SOURCES = $$PWD/tst_qhashfunctions.cpp
diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
index f76f3aa0c6..00ee5763ed 100644
--- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
+++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
@@ -1,34 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QVarLengthArray>
#include <qhash.h>
+#include <qfloat16.h>
#include <iterator>
#include <sstream>
@@ -40,22 +18,32 @@ class tst_QHashFunctions : public QObject
{
Q_OBJECT
public:
- enum {
- // random value
- RandomSeed = 1045982819
- };
- uint seed;
+ // random values
+ static constexpr quint64 ZeroSeed = 0;
+ static constexpr quint64 RandomSeed32 = 1045982819;
+ static constexpr quint64 RandomSeed64 = QtPrivate::QHashCombine{}(RandomSeed32, RandomSeed32);
+ size_t seed;
+
+ template <typename T1, typename T2> void stdPair_template(const T1 &t1, const T2 &t2);
public slots:
void initTestCase();
void init();
private Q_SLOTS:
- void consistent();
+ void unsignedIntegerConsistency_data();
+ void unsignedIntegerConsistency();
+ void signedIntegerConsistency_data();
+ void signedIntegerConsistency();
+ void extendedIntegerConsistency();
+ void floatingPointConsistency_data();
+ void floatingPointConsistency();
+ void stringConsistency_data();
+ void stringConsistency();
void qhash();
void qhash_of_empty_and_null_qstring();
void qhash_of_empty_and_null_qbytearray();
- void fp_qhash_of_zero_is_seed();
+ void qhash_of_zero_floating_points();
void qthash_data();
void qthash();
void range();
@@ -63,33 +51,289 @@ private Q_SLOTS:
void stdHash();
+ void stdPair_int_int() { stdPair_template(1, 2); }
+ void stdPair_ulong_llong() { stdPair_template(1UL, -2LL); }
+ void stdPair_ullong_long() { stdPair_template(1ULL, -2L); }
+ void stdPair_string_int() { stdPair_template(QString("Hello"), 2); }
+ void stdPair_int_string() { stdPair_template(1, QString("Hello")); }
+ void stdPair_bytearray_string() { stdPair_template(QByteArray("Hello"), QString("World")); }
+ void stdPair_string_bytearray() { stdPair_template(QString("Hello"), QByteArray("World")); }
+ void stdPair_int_pairIntInt() { stdPair_template(1, std::make_pair(2, 3)); }
+ void stdPair_2x_pairIntInt() { stdPair_template(std::make_pair(1, 2), std::make_pair(2, 3)); }
+ void stdPair_string_pairIntInt() { stdPair_template(QString("Hello"), std::make_pair(42, -47)); } // QTBUG-92910
+ void stdPair_int_pairIntPairIntInt() { stdPair_template(1, std::make_pair(2, std::make_pair(3, 4))); }
+
+ void enum_int_consistent_hash_qtbug108032();
+
+#if QT_DEPRECATED_SINCE(6, 6)
void setGlobalQHashSeed();
+#endif
};
-void tst_QHashFunctions::consistent()
+void tst_QHashFunctions::initTestCase()
{
- // QString-like
- {
- const QString s = QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16);
+ QTest::addColumn<quint64>("seedValue");
+
+ QTest::newRow("zero-seed") << ZeroSeed;
+ QTest::newRow("zero-seed-negated") << ~ZeroSeed;
+ QTest::newRow("non-zero-seed-32bit") << RandomSeed32;
+ QTest::newRow("non-zero-seed-32bit-negated")
+ << quint64{~quint32(RandomSeed32)}; // ensure this->seed gets same value on 32/64-bit
+ if constexpr (sizeof(size_t) == sizeof(quint64)) {
+ QTest::newRow("non-zero-seed-64bit") << RandomSeed64;
+ QTest::newRow("non-zero-seed-64bit-negated") << ~RandomSeed64;
+ }
+}
+
+void tst_QHashFunctions::init()
+{
+ QFETCH_GLOBAL(quint64, seedValue);
+ seed = size_t(seedValue);
+}
- QCOMPARE(qHash(s), qHash(QStringRef(&s)));
- QCOMPARE(qHash(s), qHash(QStringView(s)));
+template <typename T> static void addPositiveCommonRows()
+{
+ QTest::addRow("zero") << T(0);
+ QTest::addRow("positive_7bit") << T(42);
+ QTest::addRow("positive_15bit") << T(0x1f3f);
+ QTest::addRow("positive_31bit") << T(0x4b3d'93c4);
+ QTest::addRow("positive_63bit") << T(Q_INT64_C(0x39df'7338'4b14'fcb0));
+
+ QTest::addRow("SCHAR_MAX") << T(SCHAR_MAX);
+ QTest::addRow("SHRT_MAX") << T(SHRT_MAX);
+ QTest::addRow("INT_MAX") << T(INT_MAX);
+ QTest::addRow("LLONG_MAX") << T(LLONG_MAX);
+}
+
+void tst_QHashFunctions::signedIntegerConsistency_data()
+{
+ QTest::addColumn<qint64>("value");
+ addPositiveCommonRows<qint64>();
+ QTest::addRow("negative_7bit") << Q_INT64_C(-28);
+ QTest::addRow("negative_15bit") << Q_INT64_C(-0x387c);
+ QTest::addRow("negative_31bit") << qint64(-0x7713'30f9);
+
+ QTest::addRow("SCHAR_MIN") << qint64(SCHAR_MIN);
+ QTest::addRow("SHRT_MIN") << qint64(SHRT_MIN);
+ QTest::addRow("INT_MIN") << qint64(INT_MIN);
+ QTest::addRow("LLONG_MIN") << LLONG_MIN;
+}
+
+void tst_QHashFunctions::unsignedIntegerConsistency_data()
+{
+ QTest::addColumn<quint64>("value");
+ addPositiveCommonRows<quint64>();
+
+ QTest::addRow("positive_8bit") << Q_UINT64_C(0xE4);
+ QTest::addRow("positive_16bit") << Q_UINT64_C(0xcafe);
+ QTest::addRow("positive_32bit") << quint64(0xcafe'babe);
+
+ QTest::addRow("UCHAR_MAX") << quint64(UCHAR_MAX);
+ QTest::addRow("UHRT_MAX") << quint64(USHRT_MAX);
+ QTest::addRow("UINT_MAX") << quint64(UINT_MAX);
+ QTest::addRow("ULLONG_MAX") << ULLONG_MAX;
+}
+
+static void unsignedIntegerConsistency(quint64 value, size_t seed)
+{
+ quint8 v8 = quint8(value);
+ quint16 v16 = quint16(value);
+ quint32 v32 = quint32(value);
+
+ const auto hu8 = qHash(v8, seed);
+ const auto hu16 = qHash(v16, seed);
+ const auto hu32 = qHash(v32, seed);
+ const auto hu64 = qHash(value, seed);
+
+ if (v8 == value)
+ QCOMPARE(hu8, hu32);
+ if (v16 == value)
+ QCOMPARE(hu16, hu32);
+ if (v32 == value)
+ QCOMPARE(hu64, hu32);
+
+#if QT_SUPPORTS_INT128
+ const auto hu128 = qHash(quint128(value), seed);
+ QCOMPARE(hu128, hu64);
+#endif
+
+ // there are a few more unsigned types:
+#ifdef __cpp_char8_t
+ const auto hc8 = qHash(char8_t(value), seed);
+#endif
+ const auto hc16 = qHash(char16_t(value), seed);
+ const auto hc32 = qHash(char32_t(value), seed);
+#ifdef __cpp_char8_t
+ QCOMPARE(hc8, hu8);
+#endif
+ QCOMPARE(hc16, hu16);
+ QCOMPARE(hc32, hu32);
+}
+
+void tst_QHashFunctions::unsignedIntegerConsistency()
+{
+ QFETCH(quint64, value);
+ ::unsignedIntegerConsistency(value, seed);
+}
+
+void tst_QHashFunctions::signedIntegerConsistency()
+{
+ QFETCH(qint64, value);
+ qint8 v8 = qint8(value);
+ qint16 v16 = qint16(value);
+ qint32 v32 = qint32(value);
+
+ const auto hs8 = qHash(v8, seed);
+ const auto hs16 = qHash(v16, seed);
+ const auto hs32 = qHash(v32, seed);
+ const auto hs64 = qHash(value, seed);
+
+ if (v8 == value)
+ QCOMPARE(hs8, hs32);
+ if (v16 == value)
+ QCOMPARE(hs16, hs32);
+ if (v32 == value) {
+ // because of QTBUG-116080, this may not match, but we can't guarantee
+ // it mismatches 100% of the time either
+ if constexpr (sizeof(size_t) > sizeof(int) || QT_VERSION_MAJOR > 6)
+ QCOMPARE(hs64, hs32);
+ }
+
+#if QT_SUPPORTS_INT128
+ const auto hs128 = qHash(qint128(value), seed);
+ QCOMPARE(hs128, hs64);
+#endif
+
+ if (value > 0) {
+ quint64 u64 = quint64(value);
+ const auto hu64 = qHash(u64, seed);
+ QCOMPARE(hu64, hs64);
+ ::unsignedIntegerConsistency(u64, seed);
+ // by A == B && B == C -> A == C, we've shown hsXX == huXX for all XX
}
}
-void tst_QHashFunctions::initTestCase()
+void tst_QHashFunctions::extendedIntegerConsistency()
+{
+#ifdef QT_SUPPORTS_INT128
+ // We only need to check qint128 and quint128 consistency here.
+ qint128 v65bit = Q_INT128_C(0x1'abea'06b7'dcf5'106a);
+ qint128 v127bit = Q_INT128_C(0x387c'ac7a'22a0'5242'9ee9'bcaa'6a53'13af);
+
+ QCOMPARE(qHash(quint128(v65bit), seed), qHash(v65bit, seed));
+ QCOMPARE(qHash(quint128(v127bit), seed), qHash(v127bit, seed));
+#else
+ QSKIP("This platform does not support extended integer types.");
+#endif
+}
+
+void tst_QHashFunctions::floatingPointConsistency_data()
{
- Q_STATIC_ASSERT(int(RandomSeed) > 0);
+ QTest::addColumn<double>("value");
+ QTest::addRow("zero") << 0.0;
- QTest::addColumn<uint>("seedValue");
- QTest::newRow("zero-seed") << 0U;
- QTest::newRow("non-zero-seed") << uint(RandomSeed);
+ QTest::addRow("1.0") << 1.0;
+ QTest::addRow("infinity") << std::numeric_limits<double>::infinity();
+
+ QTest::addRow("fp16_epsilon") << double(std::numeric_limits<qfloat16>::epsilon());
+ QTest::addRow("fp16_min") << double(std::numeric_limits<qfloat16>::min());
+ QTest::addRow("fp16_max") << double(std::numeric_limits<qfloat16>::max());
+
+ QTest::addRow("float_epsilon") << double(std::numeric_limits<float>::epsilon());
+ QTest::addRow("float_min") << double(std::numeric_limits<float>::min());
+ QTest::addRow("float_max") << double(std::numeric_limits<float>::max());
+
+ QTest::addRow("double_epsilon") << double(std::numeric_limits<double>::epsilon());
+ QTest::addRow("double_min") << double(std::numeric_limits<double>::min());
+ QTest::addRow("double_max") << double(std::numeric_limits<double>::max());
}
-void tst_QHashFunctions::init()
+void tst_QHashFunctions::floatingPointConsistency()
+{
+ QFETCH(double, value);
+ long double lvalue = value;
+ float fp32 = float(value);
+ qfloat16 fp16 = qfloat16(value);
+
+ const auto hfld = qHash(lvalue, seed);
+ const auto hf64 = qHash(value, seed);
+ const auto hf32 = qHash(fp32, seed);
+ const auto hf16 = qHash(fp16, seed);
+
+ const auto hnfld = qHash(-lvalue, seed);
+ const auto hnf64 = qHash(-value, seed);
+ const auto hnf32 = qHash(-fp32, seed);
+ const auto hnf16 = qHash(-fp16, seed);
+
+ if (fp16 == fp32) {
+ QCOMPARE(hf16, hf32);
+ QCOMPARE(hnf16, hnf32);
+ }
+
+ // See QTBUG-116077; the rest isn't guaranteed to match (but we can't
+ // guarantee it will mismatch either).
+ return;
+
+ if (fp32 == value) {
+ QCOMPARE(hf32, hf64);
+ QCOMPARE(hnf32, hnf64);
+ }
+
+ QCOMPARE(hfld, hf64);
+ QCOMPARE(hnfld, hnf64);
+}
+
+void tst_QHashFunctions::stringConsistency_data()
{
- QFETCH_GLOBAL(uint, seedValue);
- seed = seedValue;
+ QTest::addColumn<QString>("value");
+ QTest::newRow("null") << QString();
+ QTest::newRow("empty") << "";
+ QTest::newRow("withnull") << QStringLiteral("A\0z");
+ QTest::newRow("short-ascii") << "Hello"; // 10 bytes
+ QTest::newRow("medium-ascii") << "Hello, World"; // 24 bytes
+ QTest::newRow("long-ascii") << QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16);
+
+ QTest::newRow("short-latin1") << "Bokmål";
+ QTest::newRow("medium-latin1") << "Det går bra!"; // 24 bytes
+ QTest::newRow("long-latin1")
+ << R"(Alle mennesker er født frie og med samme menneskeverd og menneskerettigheter.
+ De er utstyrt med fornuft og samvittighet og bør handle mot hverandre i brorskapets ånd.)";
+
+ QTest::newRow("short-nonlatin1") << "Ελληνικά";
+ QTest::newRow("long-nonlatin1")
+ << R"('Ολοι οι άνθρωποι γεννιούνται ελεύθεροι και ίσοι στην αξιοπρέπεια και τα
+ δικαιώματα. Είναι προικισμένοι με λογική και συνείδηση, και οφείλουν να συμπεριφέρονται μεταξύ
+ τους με πνεύμα αδελφοσύνης.)";
+}
+
+void tst_QHashFunctions::stringConsistency()
+{
+ QFETCH(QString, value);
+ QStringView sv = value;
+ QByteArray u8ba = value.toUtf8();
+ QByteArray u8bav = u8ba;
+
+ // sanity checking:
+ QCOMPARE(sv.isNull(), value.isNull());
+ QCOMPARE(sv.isEmpty(), value.isEmpty());
+ QCOMPARE(u8ba.isNull(), value.isNull());
+ QCOMPARE(u8ba.isEmpty(), value.isEmpty());
+ QCOMPARE(u8bav.isNull(), value.isNull());
+ QCOMPARE(u8bav.isEmpty(), value.isEmpty());
+
+ QCOMPARE(qHash(sv, seed), qHash(value, seed));
+ QCOMPARE(qHash(u8bav, seed), qHash(u8ba, seed));
+
+ if (seed == 0 || QHashHeterogeneousSearch<QString, QLatin1StringView>::value) {
+ QByteArray l1ba = value.toLatin1();
+ QLatin1StringView l1sv(l1ba.data(), l1ba.size());
+#ifdef Q_PROCESSOR_ARM
+ // zero-extending aeshash not implemented on ARM
+#else
+ if (value == l1sv)
+ QCOMPARE(qHash(l1sv, seed), qHash(value, seed));
+#endif
+ }
}
void tst_QHashFunctions::qhash()
@@ -97,7 +341,6 @@ void tst_QHashFunctions::qhash()
{
QBitArray a1;
QBitArray a2;
- QCOMPARE(qHash(a1, seed), seed);
a1.resize(1);
a1.setBit(0, true);
@@ -105,8 +348,8 @@ void tst_QHashFunctions::qhash()
a2.resize(1);
a2.setBit(0, false);
- uint h1 = qHash(a1, seed);
- uint h2 = qHash(a2, seed);
+ size_t h1 = qHash(a1, seed);
+ size_t h2 = qHash(a2, seed);
QVERIFY(h1 != h2); // not guaranteed
@@ -124,14 +367,14 @@ void tst_QHashFunctions::qhash()
QVERIFY(h1 == h2);
a2.setBit(0, false);
- uint h3 = qHash(a2, seed);
+ size_t h3 = qHash(a2, seed);
QVERIFY(h2 != h3); // not guaranteed
a2.setBit(0, true);
QVERIFY(h2 == qHash(a2, seed));
a2.setBit(6, false);
- uint h4 = qHash(a2, seed);
+ size_t h4 = qHash(a2, seed);
QVERIFY(h2 != h4); // not guaranteed
a2.setBit(6, true);
@@ -177,10 +420,6 @@ void tst_QHashFunctions::qhash_of_empty_and_null_qstring()
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));
@@ -193,18 +432,11 @@ void tst_QHashFunctions::qhash_of_empty_and_null_qbytearray()
QCOMPARE(qHash(null, seed), qHash(empty, seed));
}
-void tst_QHashFunctions::fp_qhash_of_zero_is_seed()
+void tst_QHashFunctions::qhash_of_zero_floating_points()
{
- QCOMPARE(qHash(-0.0f, seed), seed);
- QCOMPARE(qHash( 0.0f, seed), seed);
-
- QCOMPARE(qHash(-0.0 , seed), seed);
- QCOMPARE(qHash( 0.0 , seed), seed);
-
-#ifndef Q_OS_DARWIN
- QCOMPARE(qHash(-0.0L, seed), seed);
- QCOMPARE(qHash( 0.0L, seed), seed);
-#endif
+ QCOMPARE(qHash(-0.0f, seed), qHash(0.0f, seed));
+ QCOMPARE(qHash(-0.0 , seed), qHash(0.0 , seed));
+ QCOMPARE(qHash(-0.0L, seed), qHash(0.0L, seed));
}
void tst_QHashFunctions::qthash_data()
@@ -228,10 +460,16 @@ void tst_QHashFunctions::qthash()
namespace SomeNamespace {
struct Hashable { int i; };
- inline uint qHash(Hashable h, uint seed = 0)
+ inline size_t qHash(Hashable h, size_t seed = 0)
{ return QT_PREPEND_NAMESPACE(qHash)(h.i, seed); }
-}
+ struct AdlHashable {
+ int i;
+ private:
+ friend size_t qHash(AdlHashable h, size_t seed = 0)
+ { return QT_PREPEND_NAMESPACE(qHash)(h.i, seed); }
+ };
+}
void tst_QHashFunctions::range()
{
static const int ints[] = {0, 1, 2, 3, 4, 5};
@@ -246,17 +484,23 @@ void tst_QHashFunctions::range()
{
// verify that the input iterator category suffices:
std::stringstream sstream;
- Q_STATIC_ASSERT((std::is_same<std::input_iterator_tag, std::istream_iterator<int>::iterator_category>::value));
+ static_assert((std::is_same<std::input_iterator_tag, std::istream_iterator<int>::iterator_category>::value));
std::copy(ints, ints + numInts, std::ostream_iterator<int>(sstream, " "));
sstream.seekg(0);
std::istream_iterator<int> it(sstream), end;
QCOMPARE(qHashRange(ints, ints + numInts, seed), qHashRange(it, end, seed));
}
- SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
- static const size_t numHashables = sizeof hashables / sizeof *hashables;
- // compile check: is qHash() found using ADL?
- (void)qHashRange(hashables, hashables + numHashables, seed);
+ {
+ SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
+ // compile check: is qHash() found using ADL?
+ [[maybe_unused]] auto r = qHashRange(std::begin(hashables), std::end(hashables), seed);
+ }
+ {
+ SomeNamespace::AdlHashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
+ // compile check: is qHash() found as a hidden friend?
+ [[maybe_unused]] auto r = qHashRange(std::begin(hashables), std::end(hashables), seed);
+ }
}
void tst_QHashFunctions::rangeCommutative()
@@ -279,15 +523,47 @@ void tst_QHashFunctions::rangeCommutative()
QCOMPARE(qHashRangeCommutative(ints, ints + numInts, seed), qHashRangeCommutative(it, end, seed));
}
- SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
- static const size_t numHashables = sizeof hashables / sizeof *hashables;
- // compile check: is qHash() found using ADL?
- (void)qHashRangeCommutative(hashables, hashables + numHashables, seed);
+ {
+ SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
+ // compile check: is qHash() found using ADL?
+ [[maybe_unused]] auto r = qHashRangeCommutative(std::begin(hashables), std::end(hashables), seed);
+ }
+ {
+ SomeNamespace::AdlHashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
+ // compile check: is qHash() found as a hidden friend?
+ [[maybe_unused]] auto r = qHashRangeCommutative(std::begin(hashables), std::end(hashables), seed);
+ }
}
+// QVarLengthArray these days has a qHash() as a hidden friend.
+// This checks that QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH can deal with that:
+
+QT_BEGIN_NAMESPACE
+QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QVarLengthArray<QVector<int>>)
+QT_END_NAMESPACE
+
void tst_QHashFunctions::stdHash()
{
{
+ std::unordered_set<QVarLengthArray<QVector<int>>> s = {
+ {
+ {0, 1, 2},
+ {42, 43, 44},
+ {},
+ }, {
+ {11, 12, 13},
+ {},
+ },
+ };
+ QCOMPARE(s.size(), 2UL);
+ s.insert({
+ {11, 12, 13},
+ {},
+ });
+ QCOMPARE(s.size(), 2UL);
+ }
+
+ {
std::unordered_set<QString> s = {QStringLiteral("Hello"), QStringLiteral("World")};
QCOMPARE(s.size(), 2UL);
s.insert(QStringLiteral("Hello"));
@@ -315,10 +591,50 @@ void tst_QHashFunctions::stdHash()
QCOMPARE(s.size(), 2UL);
}
+ {
+ std::unordered_set<QChar> s = {u'H', u'W'};
+ QCOMPARE(s.size(), 2UL);
+ s.insert(u'H');
+ QCOMPARE(s.size(), 2UL);
+ }
+
+}
+
+template <typename T1, typename T2>
+void tst_QHashFunctions::stdPair_template(const T1 &t1, const T2 &t2)
+{
+ std::pair<T1, T2> dpair{};
+ std::pair<T1, T2> vpair{t1, t2};
+
+ // confirm proper working of the pair and of the underlying types
+ QVERIFY(t1 == t1);
+ QVERIFY(t2 == t2);
+ QCOMPARE(qHash(t1, seed), qHash(t1, seed));
+ QCOMPARE(qHash(t2, seed), qHash(t2, seed));
+
+ QVERIFY(dpair == dpair);
+ QVERIFY(vpair == vpair);
+
+ // therefore their hashes should be equal
+ QCOMPARE(qHash(dpair, seed), qHash(dpair, seed));
+ QCOMPARE(qHash(vpair, seed), qHash(vpair, seed));
+}
+
+void tst_QHashFunctions::enum_int_consistent_hash_qtbug108032()
+{
+ enum E { E1, E2, E3 };
+
+ static_assert(QHashPrivate::HasQHashSingleArgOverload<E>);
+
+ QCOMPARE(qHash(E1, seed), qHash(int(E1), seed));
+ QCOMPARE(qHash(E2, seed), qHash(int(E2), seed));
+ QCOMPARE(qHash(E3, seed), qHash(int(E3), seed));
}
+#if QT_DEPRECATED_SINCE(6, 6)
void tst_QHashFunctions::setGlobalQHashSeed()
{
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
// Setter works as advertised
qSetGlobalQHashSeed(0);
QCOMPARE(qGlobalQHashSeed(), 0);
@@ -331,7 +647,9 @@ void tst_QHashFunctions::setGlobalQHashSeed()
// Reset works as advertised
qSetGlobalQHashSeed(-1);
QVERIFY(qGlobalQHashSeed() > 0);
+QT_WARNING_POP
}
+#endif // QT_DEPRECATED_SINCE(6, 6)
QTEST_APPLESS_MAIN(tst_QHashFunctions)
#include "tst_qhashfunctions.moc"
diff --git a/tests/auto/corelib/tools/qhashseed/CMakeLists.txt b/tests/auto/corelib/tools/qhashseed/CMakeLists.txt
new file mode 100644
index 0000000000..27b4cce133
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qhashseed Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qhashseed LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qhashseed
+ SOURCES
+ tst_qhashseed.cpp
+)
+
+qt_internal_add_executable(tst_qhashseed_helper
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_qhashseed_helper.cpp
+)
diff --git a/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp b/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
new file mode 100644
index 0000000000..99fc7c5772
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
@@ -0,0 +1,186 @@
+// Copyright (C) 2021 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+
+#include <qhashfunctions.h>
+#if QT_CONFIG(process)
+#include <qprocess.h>
+#endif
+
+class tst_QHashSeed : public QObject
+{
+ Q_OBJECT
+public:
+ static void initMain();
+
+private Q_SLOTS:
+ void initTestCase();
+ void environmentVariable_data();
+ void environmentVariable();
+ void deterministicSeed();
+ void reseeding();
+ void quality();
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ void compatibilityApi();
+ void deterministicSeed_compat();
+#endif
+};
+
+void tst_QHashSeed::initMain()
+{
+ qunsetenv("QT_HASH_SEED");
+}
+
+void tst_QHashSeed::initTestCase()
+{
+ // in case the qunsetenv above didn't work
+ if (qEnvironmentVariableIsSet("QT_HASH_SEED"))
+ QSKIP("QT_HASH_SEED environment variable is set, please don't do that");
+}
+
+void tst_QHashSeed::environmentVariable_data()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("This test needs a helper binary, so is excluded from this platform.");
+#endif
+
+ QTest::addColumn<QByteArray>("envVar");
+ QTest::addColumn<bool>("isZero");
+ QTest::newRow("unset-environment") << QByteArray() << false;
+ QTest::newRow("empty-environment") << QByteArray("") << false;
+ QTest::newRow("zero-seed") << QByteArray("0") << true;
+}
+
+void tst_QHashSeed::environmentVariable()
+{
+ #if QT_CONFIG(process)
+ QFETCH(QByteArray, envVar);
+ QFETCH(bool, isZero);
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ if (envVar.isNull())
+ env.remove("QT_HASH_SEED");
+ else
+ env.insert("QT_HASH_SEED", envVar);
+
+ QProcess helper;
+ helper.setProcessEnvironment(env);
+ helper.setProgram("./tst_qhashseed_helper");
+ helper.start();
+ QVERIFY2(helper.waitForStarted(5000), qPrintable(helper.errorString()));
+ QVERIFY2(helper.waitForFinished(5000), qPrintable(helper.errorString()));
+ QCOMPARE(helper.exitStatus(), 0);
+
+ QByteArray line1 = helper.readLine().trimmed();
+ QByteArray line2 = helper.readLine().trimmed();
+ QCOMPARE(line2, line1);
+ QCOMPARE(line1 == "0", isZero);
+#endif
+}
+
+void tst_QHashSeed::deterministicSeed()
+{
+ QHashSeed::setDeterministicGlobalSeed();
+ QCOMPARE(size_t(QHashSeed::globalSeed()), size_t(0));
+
+ // now reset
+ QHashSeed::resetRandomGlobalSeed();
+ QVERIFY(QHashSeed::globalSeed() != 0);
+}
+
+void tst_QHashSeed::reseeding()
+{
+ constexpr int Iterations = 4;
+ size_t seeds[Iterations];
+ for (int i = 0; i < Iterations; ++i) {
+ seeds[i] = QHashSeed::globalSeed();
+ QHashSeed::resetRandomGlobalSeed();
+ }
+
+ // verify that they are all different
+ QString fmt = QStringLiteral("seeds[%1] = 0x%3, seeds[%2] = 0x%4");
+ for (int i = 0; i < Iterations; ++i) {
+ for (int j = i + 1; j < Iterations; ++j) {
+ QVERIFY2(seeds[i] != seeds[j],
+ qPrintable(fmt.arg(i).arg(j).arg(seeds[i], 16).arg(seeds[j], 16)));
+ }
+ }
+}
+
+void tst_QHashSeed::quality()
+{
+ // this "bad seed" is used internally in qhash.cpp and should never leak!
+ constexpr size_t BadSeed = size_t(Q_UINT64_C(0x5555'5555'5555'5555));
+
+ constexpr int Iterations = 24; // nicely divisible by 3
+ int oneThird = 0;
+ int badSeeds = 0;
+ int seedsToMinus1 = 0;
+ size_t ored = 0;
+
+ for (int i = 0; i < Iterations; ++i) {
+ size_t seed = QHashSeed::globalSeed();
+ ored |= seed;
+ int bits = qPopulationCount(quintptr(seed));
+ QVERIFY2(bits > 0, QByteArray::number(bits)); // mandatory
+
+ if (bits >= std::numeric_limits<size_t>::digits / 3)
+ ++oneThird;
+ if (seed == BadSeed)
+ ++badSeeds;
+ if (ored != size_t(-1))
+ ++seedsToMinus1;
+
+ QHashSeed::resetRandomGlobalSeed();
+ }
+
+ // report out
+ qInfo() << "Number of seeds until all bits became set:" << seedsToMinus1 << '/' << Iterations;
+ qInfo() << "Number of seeds with at least one third of the bits set:"
+ << oneThird << '/' << Iterations;
+
+ // we must have set all bits after all the iterations
+ QCOMPARE(ored, size_t(-1));
+
+ // at least one third of the seeds must have one third of all the bits set
+ QVERIFY(oneThird > (Iterations/3));
+
+ // at most one seed can be the bad seed, if 32-bit, none on 64-bit
+ if (std::numeric_limits<size_t>::digits > 32)
+ QCOMPARE(badSeeds, 0);
+ else
+ QVERIFY2(badSeeds <= 1, "badSeeds = " + QByteArray::number(badSeeds));
+
+ // we must have taken at most two thirds of the iterations to have set each
+ // bit at least once
+ QVERIFY2(seedsToMinus1 < 2*Iterations/3,
+ "seedsToMinus1 = " + QByteArray::number(seedsToMinus1));
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+QT_WARNING_DISABLE_DEPRECATED
+void tst_QHashSeed::compatibilityApi()
+{
+ int oldSeed = qGlobalQHashSeed();
+ size_t newSeed = QHashSeed::globalSeed();
+
+ QCOMPARE(size_t(oldSeed), newSeed & size_t(INT_MAX));
+}
+
+void tst_QHashSeed::deterministicSeed_compat()
+{
+ // same as above, but using the compat API
+ qSetGlobalQHashSeed(0);
+ QCOMPARE(size_t(QHashSeed::globalSeed()), size_t(0));
+ QCOMPARE(qGlobalQHashSeed(), 0);
+
+ // now reset
+ qSetGlobalQHashSeed(-1);
+ QVERIFY(QHashSeed::globalSeed() != 0);
+ QVERIFY(qGlobalQHashSeed() != 0);
+ QVERIFY(qGlobalQHashSeed() != -1); // possible, but extremely unlikely
+}
+#endif // Qt 7
+
+QTEST_MAIN(tst_QHashSeed)
+#include "tst_qhashseed.moc"
diff --git a/tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp b/tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp
new file mode 100644
index 0000000000..25e7909870
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2021 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <qhashfunctions.h>
+#include <stdio.h>
+
+int main()
+{
+ // appless:
+ QHashSeed seed1 = QHashSeed::globalSeed();
+ QHashSeed seed2 = QHashSeed::globalSeed();
+ printf("%zu\n%zu\n", size_t(seed1), size_t(seed2));
+ return 0;
+}
diff --git a/tests/auto/corelib/tools/qline/CMakeLists.txt b/tests/auto/corelib/tools/qline/CMakeLists.txt
new file mode 100644
index 0000000000..17a3a1bcef
--- /dev/null
+++ b/tests/auto/corelib/tools/qline/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qline Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qline LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qline
+ SOURCES
+ tst_qline.cpp
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qline CONDITION UNIX AND NOT APPLE AND NOT HAIKU AND NOT INTEGRITY AND NOT VXWORKS
+ LIBRARIES
+ m
+)
diff --git a/tests/auto/corelib/tools/qline/qline.pro b/tests/auto/corelib/tools/qline/qline.pro
deleted file mode 100644
index 81e2f17118..0000000000
--- a/tests/auto/corelib/tools/qline/qline.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qline
-QT = core testlib
-SOURCES = tst_qline.cpp
-unix:!darwin:!vxworks:!haiku:!integrity: LIBS+=-lm
diff --git a/tests/auto/corelib/tools/qline/tst_qline.cpp b/tests/auto/corelib/tools/qline/tst_qline.cpp
index 31aa5b4e0c..51f1f8ac79 100644
--- a/tests/auto/corelib/tools/qline/tst_qline.cpp
+++ b/tests/auto/corelib/tools/qline/tst_qline.cpp
@@ -1,38 +1,11 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <qline.h>
-#include <math.h>
+#include <qmath.h>
-#ifndef M_2PI
-#define M_2PI 6.28318530717958647692528676655900576
-#endif
+#include <array>
class tst_QLine : public QObject
{
@@ -53,11 +26,6 @@ private slots:
void testNormalVector();
void testNormalVector_data();
-#if QT_DEPRECATED_SINCE(5, 14)
- void testAngle();
- void testAngle_data();
-#endif
-
void testAngle2();
void testAngle2_data();
@@ -67,13 +35,10 @@ private slots:
void testAngleTo_data();
void testSet();
-};
-// Square root of two
-#define SQRT2 1.4142135623731
-
-// Length of unit vector projected to x from 45 degrees
-#define UNITX_45 0.707106781186547
+ void toLineF_data();
+ void toLineF();
+};
const qreal epsilon = sizeof(qreal) == sizeof(double) ? 1e-8 : 1e-4;
@@ -208,9 +173,6 @@ void tst_QLine::testIntersection()
QPointF ip;
QLineF::IntersectionType itype = a.intersects(b, &ip);
-#if QT_DEPRECATED_SINCE(5, 14)
- QCOMPARE(a.intersect(b, &ip), itype);
-#endif
QCOMPARE(int(itype), type);
if (type != QLineF::NoIntersection) {
@@ -230,30 +192,46 @@ void tst_QLine::testLength_data()
QTest::addColumn<double>("vx");
QTest::addColumn<double>("vy");
- QTest::newRow("[1,0]*2") << 0.0 << 0.0 << 1.0 << 0.0 << 1.0 << 2.0 << 2.0 << 0.0;
- QTest::newRow("[0,1]*2") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 2.0 << 0.0 << 2.0;
- QTest::newRow("[-1,0]*2") << 0.0 << 0.0 << -1.0 << 0.0 << 1.0 << 2.0 << -2.0 << 0.0;
- QTest::newRow("[0,-1]*2") << 0.0 << 0.0 << 0.0 << -1.0 << 1.0 << 2.0 << 0.0 << -2.0;
- QTest::newRow("[1,1]->|1|") << 0.0 << 0.0 << 1.0 << 1.0
- << double(SQRT2) << 1.0 << double(UNITX_45) << double(UNITX_45);
+ // Test name: [dx,dy]->|lenToSet| (x1,x2)
+ // with the last part omitted if (0,0)
+ QTest::newRow("[1,0]->|2|") << 0.0 << 0.0 << 1.0 << 0.0 << 1.0 << 2.0 << 2.0 << 0.0;
+ QTest::newRow("[0,1]->|2|") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 2.0 << 0.0 << 2.0;
+ QTest::newRow("[-1,0]->|2|") << 0.0 << 0.0 << -1.0 << 0.0 << 1.0 << 2.0 << -2.0 << 0.0;
+ QTest::newRow("[0,-1]->|2|") << 0.0 << 0.0 << 0.0 << -1.0 << 1.0 << 2.0 << 0.0 << -2.0;
+ QTest::newRow("[1,1]->->|1|") << 0.0 << 0.0 << 1.0 << 1.0
+ << M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1|") << 0.0 << 0.0 << -1.0 << 1.0
- << double(SQRT2) << 1.0 << double(-UNITX_45) << double(UNITX_45);
+ << M_SQRT2 << 1.0 << -M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[1,-1]->|1|") << 0.0 << 0.0 << 1.0 << -1.0
- << double(SQRT2) << 1.0 << double(UNITX_45) << double(-UNITX_45);
+ << M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1|") << 0.0 << 0.0 << -1.0 << -1.0
- << double(SQRT2) << 1.0 << double(-UNITX_45) << double(-UNITX_45);
- QTest::newRow("[1,0]*2 (2,2)") << 2.0 << 2.0 << 3.0 << 2.0 << 1.0 << 2.0 << 2.0 << 0.0;
- QTest::newRow("[0,1]*2 (2,2)") << 2.0 << 2.0 << 2.0 << 3.0 << 1.0 << 2.0 << 0.0 << 2.0;
- QTest::newRow("[-1,0]*2 (2,2)") << 2.0 << 2.0 << 1.0 << 2.0 << 1.0 << 2.0 << -2.0 << 0.0;
- QTest::newRow("[0,-1]*2 (2,2)") << 2.0 << 2.0 << 2.0 << 1.0 << 1.0 << 2.0 << 0.0 << -2.0;
+ << M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
+ QTest::newRow("[1,0]->|2| (2,2)") << 2.0 << 2.0 << 3.0 << 2.0 << 1.0 << 2.0 << 2.0 << 0.0;
+ QTest::newRow("[0,1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 3.0 << 1.0 << 2.0 << 0.0 << 2.0;
+ QTest::newRow("[-1,0]->|2| (2,2)") << 2.0 << 2.0 << 1.0 << 2.0 << 1.0 << 2.0 << -2.0 << 0.0;
+ QTest::newRow("[0,-1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 1.0 << 1.0 << 2.0 << 0.0 << -2.0;
QTest::newRow("[1,1]->|1| (2,2)") << 2.0 << 2.0 << 3.0 << 3.0
- << double(SQRT2) << 1.0 << double(UNITX_45) << double(UNITX_45);
+ << M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 3.0
- << double(SQRT2) << 1.0 << double(-UNITX_45) << double(UNITX_45);
+ << M_SQRT2 << 1.0 << -M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[1,-1]->|1| (2,2)") << 2.0 << 2.0 << 3.0 << 1.0
- << double(SQRT2) << 1.0 << double(UNITX_45) << double(-UNITX_45);
+ << M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 1.0
- << double(SQRT2) << 1.0 << double(-UNITX_45) << double(-UNITX_45);
+ << M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
+ const double small = qSqrt(std::numeric_limits<qreal>::denorm_min()) / 8;
+ QTest::newRow("[small,small]->|2| (-small/2,-small/2)")
+ << -(small * .5) << -(small * .5) << (small * .5) << (small * .5)
+ << (small * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
+ const double tiny = std::numeric_limits<qreal>::min() / 2;
+ QTest::newRow("[tiny,tiny]->|2| (-tiny/2,-tiny/2)")
+ << -(tiny * .5) << -(tiny * .5) << (tiny * .5) << (tiny * .5)
+ << (tiny * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
+ QTest::newRow("[1+3e-13,1+4e-13]|1895| (1, 1)")
+ << 1.0 << 1.0 << (1 + 3e-13) << (1 + 4e-13)
+ << 5e-13 << 1895.0 << 1137.0 << 1516.0;
+ QTest::newRow("[4e-323,5e-324]|1892|") // Unavoidable underflow: denormals
+ << 0.0 << 0.0 << 4e-323 << 5e-324
+ << 4e-323 << 1892.0 << 4e-323 << 5e-324; // vx, vy values ignored
}
void tst_QLine::testLength()
@@ -271,9 +249,21 @@ void tst_QLine::testLength()
QCOMPARE(l.length(), qreal(length));
l.setLength(lengthToSet);
- QCOMPARE(l.length(), qreal(lengthToSet));
- QCOMPARE(l.dx(), qreal(vx));
- QCOMPARE(l.dy(), qreal(vy));
+
+ if constexpr (std::numeric_limits<double>::has_denorm != std::denorm_present) {
+ if (qstrcmp(QTest::currentDataTag(), "[tiny,tiny]->|2| (-tiny/2,-tiny/2)") == 0
+ || qstrcmp(QTest::currentDataTag(), "[4e-323,5e-324]|1892|") == 0) {
+ QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
+ }
+ }
+ // Scaling tiny values up to big can be imprecise: don't try to test vx, vy
+ if (length > 0 && qFuzzyIsNull(length)) {
+ QVERIFY(l.length() > lengthToSet / 2 && l.length() < lengthToSet * 2);
+ } else {
+ QCOMPARE(l.length(), length > 0 ? qreal(lengthToSet) : qreal(length));
+ QCOMPARE(l.dx(), qreal(vx));
+ QCOMPARE(l.dy(), qreal(vy));
+ }
}
void tst_QLine::testCenter()
@@ -383,57 +373,6 @@ void tst_QLine::testNormalVector()
QCOMPARE(n.dy(), qreal(nvy));
}
-#if QT_DEPRECATED_SINCE(5, 14)
-void tst_QLine::testAngle_data()
-{
- QTest::addColumn<double>("xa1");
- QTest::addColumn<double>("ya1");
- QTest::addColumn<double>("xa2");
- QTest::addColumn<double>("ya2");
- QTest::addColumn<double>("xb1");
- QTest::addColumn<double>("yb1");
- QTest::addColumn<double>("xb2");
- QTest::addColumn<double>("yb2");
- QTest::addColumn<double>("angle");
-
- QTest::newRow("parallel") << 1.0 << 1.0 << 3.0 << 4.0
- << 5.0 << 6.0 << 7.0 << 9.0
- << 0.0;
- QTest::newRow("[4,4]-[4,0]") << 1.0 << 1.0 << 5.0 << 5.0
- << 0.0 << 4.0 << 3.0 << 4.0
- << 45.0;
- QTest::newRow("[4,4]-[-4,0]") << 1.0 << 1.0 << 5.0 << 5.0
- << 3.0 << 4.0 << 0.0 << 4.0
- << 135.0;
-
- for (int i=0; i<180; ++i) {
- QTest::newRow(("angle:" + QByteArray::number(i)).constData())
- << 0.0 << 0.0 << double(cos(i*M_2PI/360)) << double(sin(i*M_2PI/360))
- << 0.0 << 0.0 << 1.0 << 0.0
- << double(i);
- }
-}
-
-void tst_QLine::testAngle()
-{
- QFETCH(double, xa1);
- QFETCH(double, ya1);
- QFETCH(double, xa2);
- QFETCH(double, ya2);
- QFETCH(double, xb1);
- QFETCH(double, yb1);
- QFETCH(double, xb2);
- QFETCH(double, yb2);
- QFETCH(double, angle);
-
- QLineF a(xa1, ya1, xa2, ya2);
- QLineF b(xb1, yb1, xb2, yb2);
-
- double resultAngle = a.angle(b);
- QCOMPARE(qRound(resultAngle), qRound(angle));
-}
-#endif
-
void tst_QLine::testAngle2_data()
{
QTest::addColumn<qreal>("x1");
@@ -543,5 +482,35 @@ void tst_QLine::testAngleTo_data()
}
}
+void tst_QLine::toLineF_data()
+{
+ QTest::addColumn<QLine>("input");
+ QTest::addColumn<QLineF>("result");
+
+ auto row = [](int x1, int y1, int x2, int y2) {
+ QTest::addRow("((%d, %d)->(%d, %d))", x1, y1, x2, y2)
+ << QLine(x1, y1, x2, y2) << QLineF(x1, y1, x2, y2);
+ };
+ constexpr std::array samples = {-1, 0, 1};
+ for (int x1 : samples) {
+ for (int y1 : samples) {
+ for (int x2 : samples) {
+ for (int y2 : samples) {
+ row(x1, y1, x2, y2);
+ }
+ }
+ }
+ }
+}
+
+void tst_QLine::toLineF()
+{
+ QFETCH(const QLine, input);
+ QFETCH(const QLineF, result);
+
+ QCOMPARE(input.toLineF(), result);
+}
+
+
QTEST_MAIN(tst_QLine)
#include "tst_qline.moc"
diff --git a/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro b/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro
deleted file mode 100644
index c53d553d6d..0000000000
--- a/tests/auto/corelib/tools/qlinkedlist/qlinkedlist.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qlinkedlist
-QT = core testlib
-qtConfig(c++14): CONFIG += c++14
-qtConfig(c++1z): CONFIG += c++1z
-SOURCES = tst_qlinkedlist.cpp
-DEFINES -= QT_NO_LINKED_LIST
diff --git a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
deleted file mode 100644
index ed0abff456..0000000000
--- a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
+++ /dev/null
@@ -1,1072 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-#include <QLinkedList>
-
-struct Movable
-{
- Movable(char input = 'j') : i(input), state(Constructed)
- {
- ++liveCount;
- }
- Movable(const Movable &other)
- : i(other.i)
- , state(Constructed)
- {
- check(other.state, Constructed);
- ++liveCount;
- }
-
- ~Movable()
- {
- check(state, Constructed);
- i = 0;
- --liveCount;
- state = Destructed;
- }
-
- bool operator ==(const Movable &other) const
- {
- check(state, Constructed);
- check(other.state, Constructed);
- return i == other.i;
- }
-
- Movable &operator=(const Movable &other)
- {
- check(state, Constructed);
- check(other.state, Constructed);
- i = other.i;
- return *this;
- }
- char i;
-
- static int getLiveCount() { return liveCount; }
-private:
- static int liveCount;
-
- enum State { Constructed = 106, Destructed = 110 };
- State state;
-
- static void check(const State state1, const State state2)
- {
- QCOMPARE(int(state1), int(state2));
- }
-};
-
-int Movable::liveCount = 0;
-
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(Movable);
-
-Q_DECLARE_METATYPE(QLinkedList<int>);
-
-
-int qHash(const Movable& movable)
-{
- return qHash(movable.i);
-}
-
-struct Complex
-{
- Complex(int val = 0)
- : value(val)
- , checkSum(this)
- {
- ++liveCount;
- }
-
- Complex(Complex const &other)
- : value(other.value)
- , checkSum(this)
- {
- ++liveCount;
- }
-
- Complex &operator=(Complex const &other)
- {
- check(); other.check();
-
- value = other.value;
- return *this;
- }
-
- ~Complex()
- {
- --liveCount;
- check();
- }
-
- operator int() const { return value; }
-
- bool operator==(Complex const &other) const
- {
- check(); other.check();
- return value == other.value;
- }
-
- void check() const
- {
- QVERIFY(this == checkSum);
- }
-
- static int getLiveCount() { return liveCount; }
-private:
- static int liveCount;
-
- int value;
- void *checkSum;
-};
-
-int Complex::liveCount = 0;
-
-Q_DECLARE_METATYPE(Complex);
-
-// Tests depend on the fact that:
-Q_STATIC_ASSERT(!QTypeInfo<int>::isStatic);
-Q_STATIC_ASSERT(!QTypeInfo<int>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<Movable>::isStatic);
-Q_STATIC_ASSERT(QTypeInfo<Movable>::isComplex);
-Q_STATIC_ASSERT(QTypeInfo<Complex>::isStatic);
-Q_STATIC_ASSERT(QTypeInfo<Complex>::isComplex);
-
-class tst_QLinkedList : public QObject
-{
- Q_OBJECT
-private slots:
- void eraseValidIteratorsOnSharedList() const;
- void insertWithIteratorsOnSharedList() const;
- void lengthInt() const;
- void lengthMovable() const;
- void lengthComplex() const;
- void lengthSignature() const;
- void firstInt() const;
- void firstMovable() const;
- void firstComplex() const;
- void lastInt() const;
- void lastMovable() const;
- void lastComplex() const;
- void beginInt() const;
- void beginMovable() const;
- void beginComplex() const;
- void endInt() const;
- void endMovable() const;
- void endComplex() const;
- void containsInt() const;
- void containsMovable() const;
- void containsComplex() const;
- void countInt() const;
- void countMovable() const;
- void countComplex() const;
- void cpp17ctad() const;
- void emptyInt() const;
- void emptyMovable() const;
- void emptyComplex() const;
- void endsWithInt() const;
- void endsWithMovable() const;
- void endsWithComplex() const;
- void removeAllInt() const;
- void removeAllMovable() const;
- void removeAllComplex() const;
- void removeOneInt() const;
- void removeOneMovable() const;
- void removeOneComplex() const;
- void reverseIterators() const;
- void startsWithInt() const;
- void startsWithMovable() const;
- void startsWithComplex() const;
- void takeFirstInt() const;
- void takeFirstMovable() const;
- void takeFirstComplex() const;
- void takeLastInt() const;
- void takeLastMovable() const;
- void takeLastComplex() const;
- void toStdListInt() const;
- void toStdListMovable() const;
- void toStdListComplex() const;
- void testOperatorsInt() const;
- void testOperatorsMovable() const;
- void testOperatorsComplex() const;
- void testSTLIteratorsInt() const;
- void testSTLIteratorsMovable() const;
- void testSTLIteratorsComplex() const;
-
- void initializeList() const;
-
- void constSharedNullInt() const;
- void constSharedNullMovable() const;
- void constSharedNullComplex() const;
-private:
- template<typename T> void length() const;
- template<typename T> void first() const;
- template<typename T> void last() const;
- template<typename T> void begin() const;
- template<typename T> void end() const;
- template<typename T> void contains() const;
- template<typename T> void count() const;
- template<typename T> void empty() const;
- template<typename T> void endsWith() const;
- template<typename T> void move() const;
- template<typename T> void removeAll() const;
- template<typename T> void removeOne() const;
- template<typename T> void startsWith() const;
- template<typename T> void swap() const;
- template<typename T> void takeFirst() const;
- template<typename T> void takeLast() const;
- template<typename T> void toStdList() const;
- template<typename T> void value() const;
-
- template<typename T> void testOperators() const;
- template<typename T> void testSTLIterators() const;
-
- template<typename T> void constSharedNull() const;
-
- int dummyForGuard;
-};
-
-template<typename T> struct SimpleValue
-{
- static T at(int index)
- {
- return values[index % maxSize];
- }
- static const uint maxSize = 7;
- static const T values[maxSize];
-};
-
-template<>
-const int SimpleValue<int>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
-template<>
-const Movable SimpleValue<Movable>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
-template<>
-const Complex SimpleValue<Complex>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
-
-// Make some macros for the tests to use in order to be slightly more readable...
-#define T_FOO SimpleValue<T>::at(0)
-#define T_BAR SimpleValue<T>::at(1)
-#define T_BAZ SimpleValue<T>::at(2)
-#define T_CAT SimpleValue<T>::at(3)
-#define T_DOG SimpleValue<T>::at(4)
-#define T_BLAH SimpleValue<T>::at(5)
-#define T_WEEE SimpleValue<T>::at(6)
-
-template<typename T>
-void tst_QLinkedList::length() const
-{
- /* Empty list. */
- {
- const QLinkedList<T> list;
- QCOMPARE(list.size(), 0);
- }
-
- /* One entry. */
- {
- QLinkedList<T> list;
- list.append(T_FOO);
- QCOMPARE(list.size(), 1);
- }
-
- /* Two entries. */
- {
- QLinkedList<T> list;
- list.append(T_FOO);
- list.append(T_BAR);
- QCOMPARE(list.size(), 2);
- }
-
- /* Three entries. */
- {
- QLinkedList<T> list;
- list.append(T_FOO);
- list.append(T_BAR);
- list.append(T_BAZ);
- QCOMPARE(list.size(), 3);
- }
-}
-
-void tst_QLinkedList::eraseValidIteratorsOnSharedList() const
-{
- QLinkedList<int> a, b;
- a.append(5);
- a.append(10);
- a.append(20);
- a.append(20);
- a.append(20);
- a.append(20);
- a.append(30);
-
- QLinkedList<int>::iterator i = a.begin();
- ++i;
- ++i;
- ++i;
- b = a;
- QLinkedList<int>::iterator r = a.erase(i);
- QCOMPARE(b.size(), 7);
- QCOMPARE(a.size(), 6);
- --r;
- --r;
- QCOMPARE(*r, 10); // Ensure that number 2 instance was removed;
-}
-
-void tst_QLinkedList::insertWithIteratorsOnSharedList() const
-{
- QLinkedList<int> a, b;
- a.append(5);
- a.append(10);
- a.append(20);
- QLinkedList<int>::iterator i = a.begin();
- ++i;
- ++i;
- b = a;
-
- QLinkedList<int>::iterator i2 = a.insert(i, 15);
- QCOMPARE(b.size(), 3);
- QCOMPARE(a.size(), 4);
- --i2;
- QCOMPARE(*i2, 10);
-}
-
-void tst_QLinkedList::lengthInt() const
-{
- length<int>();
-}
-
-void tst_QLinkedList::lengthMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- length<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::lengthComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- length<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-void tst_QLinkedList::lengthSignature() const
-{
- /* Constness. */
- {
- const QLinkedList<int> list;
- /* The function should be const. */
- list.size();
- }
-}
-
-template<typename T>
-void tst_QLinkedList::first() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR;
-
- QCOMPARE(list.first(), T_FOO);
-
- // remove an item, make sure it still works
- list.pop_front();
- QVERIFY(list.size() == 1);
- QCOMPARE(list.first(), T_BAR);
-}
-
-void tst_QLinkedList::firstInt() const
-{
- first<int>();
-}
-
-void tst_QLinkedList::firstMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- first<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::firstComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- first<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::last() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR;
-
- QCOMPARE(list.last(), T_BAR);
-
- // remove an item, make sure it still works
- list.pop_back();
- QVERIFY(list.size() == 1);
- QCOMPARE(list.last(), T_FOO);
-}
-
-void tst_QLinkedList::lastInt() const
-{
- last<int>();
-}
-
-void tst_QLinkedList::lastMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- last<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::lastComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- last<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::begin() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR;
-
- QCOMPARE(*list.begin(), T_FOO);
-
- // remove an item, make sure it still works
- list.pop_front();
- QVERIFY(list.size() == 1);
- QCOMPARE(*list.begin(), T_BAR);
-}
-
-void tst_QLinkedList::beginInt() const
-{
- begin<int>();
-}
-
-void tst_QLinkedList::beginMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- begin<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::beginComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- begin<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::end() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR;
-
- QCOMPARE(*--list.end(), T_BAR);
-
- // remove an item, make sure it still works
- list.pop_back();
- QVERIFY(list.size() == 1);
- QCOMPARE(*--list.end(), T_FOO);
-}
-
-void tst_QLinkedList::endInt() const
-{
- end<int>();
-}
-
-void tst_QLinkedList::endMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- end<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::endComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- end<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::contains() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- QVERIFY(list.contains(T_FOO));
- QVERIFY(list.contains(T_BLAH) != true);
-
- // add it and make sure it matches
- list.append(T_BLAH);
- QVERIFY(list.contains(T_BLAH));
-}
-
-void tst_QLinkedList::containsInt() const
-{
- contains<int>();
-}
-
-void tst_QLinkedList::containsMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- contains<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::containsComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- contains<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::count() const
-{
- QLinkedList<T> list;
-
- // starts empty
- QVERIFY(list.count() == 0);
-
- // goes up
- list.append(T_FOO);
- QVERIFY(list.count() == 1);
-
- // and up
- list.append(T_BAR);
- QVERIFY(list.count() == 2);
-
- // and down
- list.pop_back();
- QVERIFY(list.count() == 1);
-
- // and empty. :)
- list.pop_back();
- QVERIFY(list.count() == 0);
-}
-
-void tst_QLinkedList::countInt() const
-{
- count<int>();
-}
-
-void tst_QLinkedList::countMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- count<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::countComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- count<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-void tst_QLinkedList::cpp17ctad() const
-{
-#ifdef __cpp_deduction_guides
-#define QVERIFY_IS_LIST_OF(obj, Type) \
- QVERIFY2((std::is_same<decltype(obj), QLinkedList<Type>>::value), \
- QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>()))
-#define CHECK(Type, One, Two, Three) \
- do { \
- const Type v[] = {One, Two, Three}; \
- QLinkedList v1 = {One, Two, Three}; \
- QVERIFY_IS_LIST_OF(v1, Type); \
- QLinkedList v2(v1.begin(), v1.end()); \
- QVERIFY_IS_LIST_OF(v2, Type); \
- QLinkedList v3(std::begin(v), std::end(v)); \
- QVERIFY_IS_LIST_OF(v3, Type); \
- } while (false) \
- /*end*/
- CHECK(int, 1, 2, 3);
- CHECK(double, 1.0, 2.0, 3.0);
- CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
-#undef QVERIFY_IS_LIST_OF
-#undef CHECK
-#else
- QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler.");
-#endif
-}
-
-template<typename T>
-void tst_QLinkedList::empty() const
-{
- QLinkedList<T> list;
-
- // make sure it starts empty
- QVERIFY(list.empty());
-
- // and doesn't stay empty
- list.append(T_FOO);
- QVERIFY(!list.empty());
-
- // and goes back to being empty
- list.pop_back();
- QVERIFY(list.empty());
-}
-
-void tst_QLinkedList::emptyInt() const
-{
- empty<int>();
-}
-
-void tst_QLinkedList::emptyMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- empty<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::emptyComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- empty<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::endsWith() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // test it returns correctly in both cases
- QVERIFY(list.endsWith(T_BAZ));
- QVERIFY(!list.endsWith(T_BAR));
-
- // remove an item and make sure the end item changes
- list.pop_back();
- QVERIFY(list.endsWith(T_BAR));
-}
-
-void tst_QLinkedList::endsWithInt() const
-{
- endsWith<int>();
-}
-
-void tst_QLinkedList::endsWithMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- endsWith<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::endsWithComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- endsWith<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::removeAll() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // remove one instance
- list.removeAll(T_BAR);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
-
- // many instances
- list << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ;
- list.removeAll(T_BAR);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
-
- // try remove something that doesn't exist
- list.removeAll(T_WEEE);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
-}
-
-void tst_QLinkedList::removeAllInt() const
-{
- removeAll<int>();
-}
-
-void tst_QLinkedList::removeAllMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- removeAll<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::removeAllComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- removeAll<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::removeOne() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // middle
- list.removeOne(T_BAR);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
-
- // start
- list.removeOne(T_FOO);
- QCOMPARE(list, QLinkedList<T>() << T_BAZ);
-
- // last
- list.removeOne(T_BAZ);
- QCOMPARE(list, QLinkedList<T>());
-
- // make sure it really only removes one :)
- list << T_FOO << T_FOO;
- list.removeOne(T_FOO);
- QCOMPARE(list, QLinkedList<T>() << T_FOO);
-
- // try remove something that doesn't exist
- list.removeOne(T_WEEE);
- QCOMPARE(list, QLinkedList<T>() << T_FOO);
-}
-
-void tst_QLinkedList::removeOneInt() const
-{
- removeOne<int>();
-}
-
-void tst_QLinkedList::removeOneMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- removeOne<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::removeOneComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- removeOne<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-void tst_QLinkedList::reverseIterators() const
-{
- QLinkedList<int> l;
- l << 1 << 2 << 3 << 4;
- QLinkedList<int> lr = l;
- std::reverse(lr.begin(), lr.end());
- const QLinkedList<int> &clr = lr;
- QVERIFY(std::equal(l.begin(), l.end(), lr.rbegin()));
- QVERIFY(std::equal(l.begin(), l.end(), lr.crbegin()));
- QVERIFY(std::equal(l.begin(), l.end(), clr.rbegin()));
- QVERIFY(std::equal(lr.rbegin(), lr.rend(), l.begin()));
- QVERIFY(std::equal(lr.crbegin(), lr.crend(), l.begin()));
- QVERIFY(std::equal(clr.rbegin(), clr.rend(), l.begin()));
-}
-
-template<typename T>
-void tst_QLinkedList::startsWith() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // make sure it starts ok
- QVERIFY(list.startsWith(T_FOO));
-
- // remove an item
- list.removeFirst();
- QVERIFY(list.startsWith(T_BAR));
-}
-
-void tst_QLinkedList::startsWithInt() const
-{
- startsWith<int>();
-}
-
-void tst_QLinkedList::startsWithMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- startsWith<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::startsWithComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- startsWith<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::takeFirst() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- QCOMPARE(list.takeFirst(), T_FOO);
- QVERIFY(list.size() == 2);
- QCOMPARE(list.takeFirst(), T_BAR);
- QVERIFY(list.size() == 1);
- QCOMPARE(list.takeFirst(), T_BAZ);
- QVERIFY(list.size() == 0);
-}
-
-void tst_QLinkedList::takeFirstInt() const
-{
- takeFirst<int>();
-}
-
-void tst_QLinkedList::takeFirstMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- takeFirst<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::takeFirstComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- takeFirst<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::takeLast() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- QCOMPARE(list.takeLast(), T_BAZ);
- QCOMPARE(list.takeLast(), T_BAR);
- QCOMPARE(list.takeLast(), T_FOO);
-}
-
-void tst_QLinkedList::takeLastInt() const
-{
- takeLast<int>();
-}
-
-void tst_QLinkedList::takeLastMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- takeLast<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::takeLastComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- takeLast<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::toStdList() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // yuck.
- std::list<T> slist;
- slist.push_back(T_FOO);
- slist.push_back(T_BAR);
- slist.push_back(T_BAZ);
-
- QCOMPARE(list.toStdList(), slist);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ);
-}
-
-void tst_QLinkedList::toStdListInt() const
-{
- toStdList<int>();
-}
-
-void tst_QLinkedList::toStdListMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- toStdList<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::toStdListComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- toStdList<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::testOperators() const
-{
- QLinkedList<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- QLinkedList<T> listtwo;
- listtwo << T_FOO << T_BAR << T_BAZ;
-
- // test equal
- QVERIFY(list == listtwo);
-
- // not equal
- listtwo.append(T_CAT);
- QVERIFY(list != listtwo);
-
- // +=
- list += listtwo;
- QVERIFY(list.size() == 7);
- QVERIFY(listtwo.size() == 4);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ
- << T_FOO << T_BAR << T_BAZ << T_CAT);
-
- // =
- list = listtwo;
- QCOMPARE(list, listtwo);
- QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ << T_CAT);
-}
-
-void tst_QLinkedList::testOperatorsInt() const
-{
- testOperators<int>();
-}
-
-void tst_QLinkedList::testOperatorsMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- testOperators<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::testOperatorsComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- testOperators<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-template<typename T>
-void tst_QLinkedList::testSTLIterators() const
-{
- QLinkedList<T> list;
-
- // create a list
- list << T_FOO << T_BAR << T_BAZ;
- typename QLinkedList<T>::iterator it = list.begin();
- QCOMPARE(*it, T_FOO); it++;
- QCOMPARE(*it, T_BAR); it++;
- QCOMPARE(*it, T_BAZ); it++;
- QCOMPARE(it, list.end()); it--;
-
- // walk backwards
- QCOMPARE(*it, T_BAZ); it--;
- QCOMPARE(*it, T_BAR); it--;
- QCOMPARE(*it, T_FOO);
-
- // test erase
- it = list.erase(it);
- QVERIFY(list.size() == 2);
- QCOMPARE(*it, T_BAR);
-
- // test multiple erase
- it = list.erase(it, it + 2);
- QVERIFY(list.size() == 0);
- QCOMPARE(it, list.end());
-
- // insert again
- it = list.insert(it, T_FOO);
- QVERIFY(list.size() == 1);
- QCOMPARE(*it, T_FOO);
-
- // insert again
- it = list.insert(it, T_BAR);
- QVERIFY(list.size() == 2);
- QCOMPARE(*it++, T_BAR);
- QCOMPARE(*it, T_FOO);
-}
-
-void tst_QLinkedList::testSTLIteratorsInt() const
-{
- testSTLIterators<int>();
-}
-
-void tst_QLinkedList::testSTLIteratorsMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- testSTLIterators<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::testSTLIteratorsComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- testSTLIterators<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-void tst_QLinkedList::initializeList() const
-{
- QLinkedList<int> v1 { 2, 3, 4 };
- QCOMPARE(v1, QLinkedList<int>() << 2 << 3 << 4);
- QCOMPARE(v1, (QLinkedList<int> { 2, 3, 4}));
-
- QLinkedList<QLinkedList<int>> v2{ v1, { 1 }, QLinkedList<int>(), { 2, 3, 4 } };
- QLinkedList<QLinkedList<int>> v3;
- v3 << v1 << (QLinkedList<int>() << 1) << QLinkedList<int>() << v1;
- QCOMPARE(v3, v2);
-}
-
-
-template<typename T>
-void tst_QLinkedList::constSharedNull() const
-{
- QLinkedList<T> list2;
- QVERIFY(!list2.isDetached());
-}
-
-void tst_QLinkedList::constSharedNullInt() const
-{
- constSharedNull<int>();
-}
-
-void tst_QLinkedList::constSharedNullMovable() const
-{
- const int liveCount = Movable::getLiveCount();
- constSharedNull<Movable>();
- QCOMPARE(liveCount, Movable::getLiveCount());
-}
-
-void tst_QLinkedList::constSharedNullComplex() const
-{
- const int liveCount = Complex::getLiveCount();
- constSharedNull<Complex>();
- QCOMPARE(liveCount, Complex::getLiveCount());
-}
-
-QTEST_APPLESS_MAIN(tst_QLinkedList)
-#include "tst_qlinkedlist.moc"
diff --git a/tests/auto/corelib/tools/qvector/.gitignore b/tests/auto/corelib/tools/qlist/.gitignore
index 5520039486..5520039486 100644
--- a/tests/auto/corelib/tools/qvector/.gitignore
+++ b/tests/auto/corelib/tools/qlist/.gitignore
diff --git a/tests/auto/corelib/tools/qlist/CMakeLists.txt b/tests/auto/corelib/tools/qlist/CMakeLists.txt
new file mode 100644
index 0000000000..fdcfcd7424
--- /dev/null
+++ b/tests/auto/corelib/tools/qlist/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlist Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlist LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlist
+ SOURCES
+ tst_qlist.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
new file mode 100644
index 0000000000..35d69e8433
--- /dev/null
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -0,0 +1,3969 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QAtomicInt>
+#include <QThread>
+#include <QSemaphore>
+#include <QAtomicScopedValueRollback>
+#include <qlist.h>
+
+
+#ifdef QT_COMPILER_HAS_LWG3346
+# if __has_include(<concepts>)
+# include <concepts>
+# if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L
+ static_assert(std::contiguous_iterator<QList<int>::iterator>);
+ static_assert(std::contiguous_iterator<QList<int>::const_iterator>);
+# endif
+# endif
+# if __has_include(<ranges>)
+# include <ranges>
+# if defined(__cpp_lib_ranges)
+ namespace rns = std::ranges;
+
+ static_assert(rns::contiguous_range<QList<int>>);
+ static_assert(rns::contiguous_range<const QList<int>>);
+# endif
+# endif
+#endif
+
+struct Movable {
+ Movable(char input = 'j')
+ : i(input)
+ , that(this)
+ , state(Constructed)
+ {
+ counter.fetchAndAddRelaxed(1);
+ }
+ Movable(const Movable &other)
+ : i(other.i)
+ , that(this)
+ , state(Constructed)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ }
+ Movable(Movable &&other)
+ : i(other.i)
+ , that(other.that)
+ , state(Constructed)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ other.that = nullptr;
+ }
+
+ ~Movable()
+ {
+ check(state, Constructed);
+ i = 0;
+ counter.fetchAndAddRelaxed(-1);
+ state = Destructed;
+ }
+
+ bool operator ==(const Movable &other) const
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ return i == other.i;
+ }
+
+ Movable &operator=(const Movable &other)
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = this;
+ return *this;
+ }
+ Movable &operator=(Movable &&other)
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = other.that;
+ other.that = nullptr;
+ return *this;
+ }
+ bool wasConstructedAt(const Movable *other) const
+ {
+ return that == other;
+ }
+ char i;
+ static QAtomicInt counter;
+private:
+ Movable *that; // used to check if an instance was moved
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state;
+
+ static void check(const State state1, const State state2)
+ {
+ QCOMPARE(int(state1), int(state2));
+ }
+};
+
+inline size_t qHash(const Movable &key, size_t seed = 0) { return qHash(key.i, seed); }
+
+QAtomicInt Movable::counter = 0;
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE);
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(Movable);
+
+struct Custom {
+ Custom(char input = 'j')
+ : i(input)
+ , that(this)
+ , state(Constructed)
+ {
+ counter.fetchAndAddRelaxed(1);
+ }
+ Custom(const Custom &other)
+ : that(this)
+ , state(Constructed)
+ {
+ check(&other);
+ counter.fetchAndAddRelaxed(1);
+ this->i = other.i;
+ }
+ ~Custom()
+ {
+ check(this);
+ i = 0;
+ counter.fetchAndAddRelaxed(-1);
+ state = Destructed;
+ QVERIFY(heapData.use_count() > 0); // otherwise it's double free
+ }
+
+ bool operator ==(const Custom &other) const
+ {
+ check(&other);
+ check(this);
+ return i == other.i;
+ }
+
+ bool operator<(const Custom &other) const
+ {
+ check(&other);
+ check(this);
+ return i < other.i;
+ }
+
+ Custom &operator=(const Custom &other)
+ {
+ check(&other);
+ check(this);
+ i = other.i;
+ return *this;
+ }
+ static QAtomicInt counter;
+
+ char i; // used to identify orgin of an instance
+private:
+ Custom *that; // used to check if an instance was moved
+ // shared_ptr triggers ASan/LSan and can track if double free happens, which
+ // is convenient to ensure there's no malfunctioning QList APIs
+ std::shared_ptr<int> heapData = std::shared_ptr<int>(new int(42));
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state;
+
+ static void check(const Custom *c)
+ {
+ // check if c object has been moved
+ QCOMPARE(c, c->that);
+ QCOMPARE(int(c->state), int(Constructed));
+ }
+};
+QAtomicInt Custom::counter = 0;
+
+inline size_t qHash(const Custom &key, size_t seed = 0) { return qHash(key.i, seed); }
+
+Q_DECLARE_METATYPE(Custom);
+
+// tests depends on the fact that:
+static_assert(QTypeInfo<int>::isRelocatable);
+static_assert(!QTypeInfo<int>::isComplex);
+static_assert(QTypeInfo<Movable>::isRelocatable);
+static_assert(QTypeInfo<Movable>::isComplex);
+static_assert(!QTypeInfo<Custom>::isRelocatable);
+static_assert(QTypeInfo<Custom>::isComplex);
+
+// leak checking utility:
+template<typename T>
+struct LeakChecker
+{
+ int instancesCount;
+ LeakChecker() : instancesCount(T::counter.loadAcquire()) { }
+ ~LeakChecker() { QCOMPARE(instancesCount, T::counter.loadAcquire()); }
+};
+template<> struct LeakChecker<int>{};
+template<> struct LeakChecker<QString>{};
+#define TST_QLIST_CHECK_LEAKS(Type) \
+ LeakChecker<Type> checker; \
+ Q_UNUSED(checker);
+
+class tst_QList : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void constructors_empty() const;
+ void constructors_emptyReserveZero() const;
+ void constructors_emptyReserve() const;
+ void constructors_reserveAndInitialize() const;
+ void copyConstructorInt() const { copyConstructor<int>(); }
+ void copyConstructorMovable() const { copyConstructor<Movable>(); }
+ void copyConstructorCustom() const { copyConstructor<Custom>(); }
+ void assignmentInt() const { testAssignment<int>(); }
+ void assignmentMovable() const { testAssignment<Movable>(); }
+ void assignmentCustom() const { testAssignment<Custom>(); }
+ void assignFromInitializerListInt() const { assignFromInitializerList<int>(); }
+ void assignFromInitializerListMovable() const { assignFromInitializerList<Movable>(); }
+ void assignFromInitializerListCustom() const { assignFromInitializerList<Custom>(); }
+ void addInt() const { add<int>(); }
+ void addMovable() const { add<Movable>(); }
+ void addCustom() const { add<Custom>(); }
+ void appendInt() const { append<int>(); }
+ void appendMovable() const { append<Movable>(); }
+ void appendCustom() const { append<Custom>(); }
+ void appendRvalue() const;
+ void appendList() const;
+ void assignEmpty() const;
+ void assignInt() const { assign<int>(); }
+ void assignMovable() const { assign<Movable>(); }
+ void assignCustom() const { assign<Custom>(); }
+ void assignUsesPrependBuffer_int_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_int() const { assignUsesPrependBuffer<int>(); }
+ void assignUsesPrependBuffer_Movable_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_Movable() const { assignUsesPrependBuffer<Movable>(); }
+ void assignUsesPrependBuffer_Custom_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_Custom() const { assignUsesPrependBuffer<Custom>(); }
+ void at() const;
+ void capacityInt() const { capacity<int>(); }
+ void capacityMovable() const { capacity<Movable>(); }
+ void capacityCustom() const { capacity<Custom>(); }
+ void clearInt() const { clear<int>(); }
+ void clearMovable() const { clear<Movable>(); }
+ void clearCustom() const { clear<Custom>(); }
+ void constData() const;
+ void constFirst() const;
+ void constLast() const;
+ void contains() const;
+ void countInt() const { count<int>(); }
+ void countMovable() const { count<Movable>(); }
+ void countCustom() const { count<Custom>(); }
+ void cpp17ctad() const;
+ void data() const;
+ void emptyInt() const { empty<int>(); }
+ void emptyMovable() const { empty<Movable>(); }
+ void emptyCustom() const { empty<Custom>(); }
+ void endsWith() const;
+ void eraseEmptyInt() const { eraseEmpty<int>(); }
+ void eraseEmptyMovable() const { eraseEmpty<Movable>(); }
+ void eraseEmptyCustom() const { eraseEmpty<Custom>(); }
+ void eraseEmptyReservedInt() const { eraseEmptyReserved<int>(); }
+ void eraseEmptyReservedMovable() const { eraseEmptyReserved<Movable>(); }
+ void eraseEmptyReservedCustom() const { eraseEmptyReserved<Custom>(); }
+ void eraseInt() const { erase<int>(false); }
+ void eraseIntShared() const { erase<int>(true); }
+ void eraseMovable() const { erase<Movable>(false); }
+ void eraseMovableShared() const { erase<Movable>(true); }
+ void eraseCustom() const { erase<Custom>(false); }
+ void eraseCustomShared() const { erase<Custom>(true); }
+ void eraseReservedInt() const { eraseReserved<int>(); }
+ void eraseReservedMovable() const { eraseReserved<Movable>(); }
+ void eraseReservedCustom() const { eraseReserved<Custom>(); }
+ void fillInt() const { fill<int>(); }
+ void fillMovable() const { fill<Movable>(); }
+ void fillCustom() const { fill<Custom>(); }
+ void fillDetachInt() const { fillDetach<int>(); }
+ void fillDetachMovable() const { fillDetach<Movable>(); }
+ void fillDetachCustom() const { fillDetach<Custom>(); }
+ void first() const;
+ void fromListInt() const { fromList<int>(); }
+ void fromListMovable() const { fromList<Movable>(); }
+ void fromListCustom() const { fromList<Custom>(); }
+ void indexOf() const;
+ void insertInt() const { insert<int>(); }
+ void insertMovable() const { insert<Movable>(); }
+ void insertCustom() const { insert<Custom>(); }
+ void insertZeroCount_data();
+ void insertZeroCount() const;
+ void isEmpty() const;
+ void last() const;
+ void lastIndexOf() const;
+ void mid() const;
+ void sliced() const;
+ void moveInt() const { move<int>(); }
+ void moveMovable() const { move<Movable>(); }
+ void moveCustom() const { move<Custom>(); }
+ void prependInt() const { prepend<int>(); }
+ void prependMovable() const { prepend<Movable>(); }
+ void prependCustom() const { prepend<Custom>(); }
+ void prependRvalue() const;
+ void qhashInt() const { qhash<int>(); }
+ void qhashMovable() const { qhash<Movable>(); }
+ void qhashCustom() const { qhash<Custom>(); }
+ void removeAllWithAlias() const;
+ void removeInt() const { remove<int>(); }
+ void removeMovable() const { remove<Movable>(); }
+ void removeCustom() const { remove<Custom>(); }
+ void removeFirstLast() const;
+ void resizePOD_data() const;
+ void resizePOD() const;
+ void resizeComplexMovable_data() const;
+ void resizeComplexMovable() const;
+ void resizeComplex_data() const;
+ void resizeComplex() const;
+ void resizeCtorAndDtor() const;
+ void resizeToZero() const;
+ void resizeToTheSameSize_data();
+ void resizeToTheSameSize() const;
+ void resizeForOverwrite() const;
+ void iterators() const;
+ void constIterators() const;
+ void reverseIterators() const;
+ void sizeInt() const { size<int>(); }
+ void sizeMovable() const { size<Movable>(); }
+ void sizeCustom() const { size<Custom>(); }
+ void startsWith() const;
+ void swapInt() const { swap<int>(); }
+ void swapMovable() const { swap<Movable>(); }
+ void swapCustom() const { swap<Custom>(); }
+ void toList() const;
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+ void fromStdVector() const;
+ void toStdVector() const;
+#endif
+ void value() const;
+ void testOperators() const;
+ void reserve();
+ void reserveZero();
+ void initializeListInt() { initializeList<int>(); }
+ void initializeListMovable() { initializeList<Movable>(); }
+ void initializeListCustom() { initializeList<Custom>(); }
+ void const_shared_null();
+ void detachInt() const { detach<int>(); }
+ void detachMovable() const { detach<Movable>(); }
+ void detachCustom() const { detach<Custom>(); }
+ void detachThreadSafetyInt() const;
+ void detachThreadSafetyMovable() const;
+ void detachThreadSafetyCustom() const;
+ void insertMove() const;
+ void swapItemsAt() const;
+ void emplaceInt() { emplaceImpl<int>(); }
+ void emplaceCustom() { emplaceImpl<Custom>(); }
+ void emplaceMovable() { emplaceImpl<Movable>(); }
+ void emplaceConsistentWithStdVectorInt() { emplaceConsistentWithStdVectorImpl<int>(); }
+ void emplaceConsistentWithStdVectorCustom() { emplaceConsistentWithStdVectorImpl<Custom>(); }
+ void emplaceConsistentWithStdVectorMovable() { emplaceConsistentWithStdVectorImpl<Movable>(); }
+ void emplaceConsistentWithStdVectorQString() { emplaceConsistentWithStdVectorImpl<QString>(); }
+ void emplaceReturnsIterator();
+ void emplaceFront() const;
+ void emplaceFrontReturnsRef() const;
+ void emplaceBack();
+ void emplaceBackReturnsRef();
+ void emplaceWithElementFromTheSameContainer();
+ void emplaceWithElementFromTheSameContainer_data();
+ void replaceInt() const { replace<int>(); }
+ void replaceCustom() const { replace<Custom>(); }
+ void replaceMovable() const { replace<Movable>(); }
+ void fromReadOnlyData() const;
+ void reallocateCustomAlignedType_qtbug90359() const;
+ void reinsertToBeginInt_qtbug91360() const { reinsertToBegin<int>(); }
+ void reinsertToBeginMovable_qtbug91360() const { reinsertToBegin<Movable>(); }
+ void reinsertToBeginCustom_qtbug91360() const { reinsertToBegin<Custom>(); }
+ void reinsertToEndInt_qtbug91360() const { reinsertToEnd<int>(); }
+ void reinsertToEndMovable_qtbug91360() const { reinsertToEnd<Movable>(); }
+ void reinsertToEndCustom_qtbug91360() const { reinsertToEnd<Custom>(); }
+ void reinsertRangeToEndInt_qtbug91360() const { reinsertRangeToEnd<int>(); }
+ void reinsertRangeToEndMovable_qtbug91360() const { reinsertRangeToEnd<Movable>(); }
+ void reinsertRangeToEndCustom_qtbug91360() const { reinsertRangeToEnd<Custom>(); }
+ // QList reference stability tests:
+ void stability_reserveInt() const { stability_reserve<int>(); }
+ void stability_reserveMovable() const { stability_reserve<Movable>(); }
+ void stability_reserveCustom() const { stability_reserve<Custom>(); }
+ void stability_eraseInt() const { stability_erase<int>(); }
+ void stability_eraseMovable() const { stability_erase<Movable>(); }
+ void stability_eraseCustom() const { stability_erase<Custom>(); }
+ void stability_appendInt() const { stability_append<int>(); }
+ void stability_appendMovable() const { stability_append<Movable>(); }
+ void stability_appendCustom() const { stability_append<Custom>(); }
+ void stability_insertElementInt() const { stability_insertElement<int>(); }
+ void stability_insertElementMovable() const { stability_insertElement<Movable>(); }
+ void stability_insertElementCustom() const { stability_insertElement<Custom>(); }
+ void stability_emplaceInt() const { stability_emplace<int>(); }
+ void stability_emplaceMovable() const { stability_emplace<Movable>(); }
+ void stability_emplaceCustom() const { stability_emplace<Custom>(); }
+ void stability_resizeInt() const { stability_resize<int>(); }
+ void stability_resizeMovable() const { stability_resize<Movable>(); }
+ void stability_resizeCustom() const { stability_resize<Custom>(); }
+
+private:
+ template<typename T> void copyConstructor() const;
+ template<typename T> void testAssignment() const;
+ template<typename T> void add() const;
+ template<typename T> void append() const;
+ template<typename T> void assign() const;
+ void assignUsesPrependBuffer_data() const;
+ template<typename T> void assignUsesPrependBuffer() const;
+ template<typename T> void assignFromInitializerList() const;
+ template<typename T> void capacity() const;
+ template<typename T> void clear() const;
+ template<typename T> void count() const;
+ template<typename T> void empty() const;
+ template<typename T> void eraseEmpty() const;
+ template<typename T> void eraseEmptyReserved() const;
+ template<typename T> void erase(bool shared) const;
+ template<typename T> void eraseReserved() const;
+ template<typename T> void fill() const;
+ template<typename T> void fillDetach() const;
+ template<typename T> void fromList() const;
+ template<typename T> void insert() const;
+ template<typename T> void qhash() const;
+ template<typename T> void move() const;
+ template<typename T> void prepend() const;
+ template<typename T> void remove() const;
+ template<typename T> void size() const;
+ template<typename T> void swap() const;
+ template<typename T> void initializeList();
+ template<typename T> void detach() const;
+ template<typename T> void detachThreadSafety() const;
+ template<typename T> void emplaceImpl() const;
+ template<typename T> void emplaceConsistentWithStdVectorImpl() const;
+ template<typename T> void replace() const;
+ template<typename T, typename Reinsert>
+ void reinsert(Reinsert op) const;
+ template<typename T>
+ void reinsertToBegin() const
+ {
+ reinsert<T>([](QList<T> &list) {
+ list.prepend(list.back());
+ list.removeLast();
+ });
+ }
+ template<typename T>
+ void reinsertToEnd() const
+ {
+ reinsert<T>([](QList<T> &list) {
+ list.append(list.front());
+ list.removeFirst();
+ });
+ }
+ template<typename T>
+ void reinsertRangeToEnd() const
+ {
+ reinsert<T>([](QList<T> &list) {
+ list.append(list.begin(), list.begin() + 1);
+ list.removeFirst();
+ });
+ }
+ template<typename T>
+ void stability_reserve() const;
+ template<typename T>
+ void stability_erase() const;
+ template<typename T>
+ void stability_append() const;
+ template<typename T, typename Insert>
+ void stability_insert(Insert op) const;
+ template<typename T>
+ void stability_resize() const;
+
+ template<typename T>
+ void stability_insertElement() const
+ {
+ stability_insert<T>(
+ [](QList<T> &list, int pos, const T &value) { list.insert(pos, 1, value); });
+ }
+ template<typename T>
+ void stability_emplace() const
+ {
+ stability_insert<T>(
+ [](QList<T> &list, int pos, const T &value) { list.emplace(pos, value); });
+ }
+};
+
+
+template<typename T> struct SimpleValue
+{
+ static T at(int index)
+ {
+ return Values[index % MaxIndex];
+ }
+
+ static QList<T> vector(int size)
+ {
+ QList<T> ret;
+ for (int i = 0; i < size; i++)
+ ret.append(at(i));
+ return ret;
+ }
+
+ static const uint MaxIndex = 6;
+ static const T Values[MaxIndex];
+};
+
+template<>
+const int SimpleValue<int>::Values[] = { 110, 105, 101, 114, 111, 98 };
+template<>
+const Movable SimpleValue<Movable>::Values[] = { 110, 105, 101, 114, 111, 98 };
+template<>
+const Custom SimpleValue<Custom>::Values[] = { 110, 105, 101, 114, 111, 98 };
+
+// Make some macros for the tests to use in order to be slightly more readable...
+#define T_FOO SimpleValue<T>::at(0)
+#define T_BAR SimpleValue<T>::at(1)
+#define T_BAZ SimpleValue<T>::at(2)
+#define T_CAT SimpleValue<T>::at(3)
+#define T_DOG SimpleValue<T>::at(4)
+#define T_BLAH SimpleValue<T>::at(5)
+
+// returns a pair of QList<T> and QList<T *>
+template<typename It>
+decltype(auto) qlistCopyAndReferenceFromRange(It first, It last)
+{
+ using T = typename std::iterator_traits<It>::value_type;
+ QList<T> copy(first, last);
+ QList<T *> reference;
+ for (; first != last; ++first)
+ reference.append(std::addressof(*first));
+ return std::make_pair(copy, reference);
+}
+
+void tst_QList::constructors_empty() const
+{
+ QList<int> emptyInt;
+ QList<Movable> emptyMovable;
+ QList<Custom> emptyCustom;
+}
+
+void tst_QList::constructors_emptyReserveZero() const
+{
+ QList<int> emptyInt(0);
+ QList<Movable> emptyMovable(0);
+ QList<Custom> emptyCustom(0);
+}
+
+void tst_QList::constructors_emptyReserve() const
+{
+ // pre-reserve capacity
+ QList<int> myInt(5);
+ QVERIFY(myInt.capacity() == 5);
+ QList<Movable> myMovable(5);
+ QVERIFY(myMovable.capacity() == 5);
+ QList<Custom> myCustom(4);
+ QVERIFY(myCustom.capacity() == 4);
+}
+
+void tst_QList::constructors_reserveAndInitialize() const
+{
+ // default-initialise items
+
+ const QList<int> myInt(5, 42);
+ QVERIFY(myInt.capacity() == 5);
+ for (int meaningoflife : myInt)
+ QCOMPARE(meaningoflife, 42);
+
+ const QList<QString> myString(5, QString::fromLatin1("c++"));
+ QVERIFY(myString.capacity() == 5);
+ // make sure all items are initialised ok
+ for (const QString &meaningoflife : myString)
+ QCOMPARE(meaningoflife, QString::fromLatin1("c++"));
+
+ const QList<Custom> myCustom(5, Custom('n'));
+ QVERIFY(myCustom.capacity() == 5);
+ // make sure all items are initialised ok
+ for (Custom meaningoflife : myCustom)
+ QCOMPARE(meaningoflife.i, 'n');
+}
+
+template<typename T>
+void tst_QList::copyConstructor() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ T value1(SimpleValue<T>::at(0));
+ T value2(SimpleValue<T>::at(1));
+ T value3(SimpleValue<T>::at(2));
+ T value4(SimpleValue<T>::at(3));
+ {
+ QList<T> v1;
+ QList<T> v2(v1);
+ QCOMPARE(v1, v2);
+ }
+ {
+ QList<T> v1;
+ v1 << value1 << value2 << value3 << value4;
+ QList<T> v2(v1);
+ QCOMPARE(v1, v2);
+ }
+}
+
+template<typename T>
+void tst_QList::testAssignment() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> v1(5);
+ QCOMPARE(v1.size(), 5);
+ QVERIFY(v1.isDetached());
+
+ QList<T> v2(7);
+ QCOMPARE(v2.size(), 7);
+ QVERIFY(v2.isDetached());
+
+ QVERIFY(!v1.isSharedWith(v2));
+
+ v1 = v2;
+
+ QVERIFY(!v1.isDetached());
+ QVERIFY(!v2.isDetached());
+ QVERIFY(v1.isSharedWith(v2));
+
+ const void *const data1 = v1.constData();
+ const void *const data2 = v2.constData();
+
+ QCOMPARE(data1, data2);
+
+ v1.clear();
+
+ QVERIFY(v2.isDetached());
+ QVERIFY(!v1.isSharedWith(v2));
+ QCOMPARE((void *)v2.constData(), data2);
+}
+
+template<typename T>
+void tst_QList::assignFromInitializerList() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ T val1(SimpleValue<T>::at(1));
+ T val2(SimpleValue<T>::at(2));
+ T val3(SimpleValue<T>::at(3));
+
+ QList<T> v1 = {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+
+ v1 = {};
+ QCOMPARE(v1.size(), 0);
+}
+
+template<typename T>
+void tst_QList::add() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ QList<T> empty1;
+ QList<T> empty2;
+ QVERIFY((empty1 + empty2).isEmpty());
+ empty1 += empty2;
+ QVERIFY(empty1.isEmpty());
+ QVERIFY(empty2.isEmpty());
+ }
+ {
+ QList<T> v(12);
+ QList<T> empty;
+ QCOMPARE((v + empty), v);
+ v += empty;
+ QVERIFY(!v.isEmpty());
+ QCOMPARE(v.size(), 12);
+ QVERIFY(empty.isEmpty());
+ }
+ {
+ QList<T> v1(12);
+ QList<T> v2;
+ v2 += v1;
+ QVERIFY(!v1.isEmpty());
+ QCOMPARE(v1.size(), 12);
+ QVERIFY(!v2.isEmpty());
+ QCOMPARE(v2.size(), 12);
+ }
+}
+
+template<typename T>
+void tst_QList::append() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ QList<T> myvec;
+ myvec.append(SimpleValue<T>::at(0));
+ QVERIFY(myvec.size() == 1);
+ myvec.append(SimpleValue<T>::at(1));
+ QVERIFY(myvec.size() == 2);
+ myvec.append(SimpleValue<T>::at(2));
+ QVERIFY(myvec.size() == 3);
+
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(0)
+ << SimpleValue<T>::at(1)
+ << SimpleValue<T>::at(2));
+ }
+ {
+ QList<T> v(2);
+ v.append(SimpleValue<T>::at(0));
+ QVERIFY(v.size() == 3);
+ QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
+ }
+ {
+ QList<T> v(2);
+ v.reserve(12);
+ v.append(SimpleValue<T>::at(0));
+ QVERIFY(v.size() == 3);
+ QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
+ }
+ {
+ QList<int> v;
+ v << 1 << 2 << 3;
+ QList<int> x;
+ x << 4 << 5 << 6;
+ v.append(x);
+
+ QList<int> combined;
+ combined << 1 << 2 << 3 << 4 << 5 << 6;
+
+ QCOMPARE(v, combined);
+ }
+ {
+ const QList<T> otherVec { SimpleValue<T>::at(0),
+ SimpleValue<T>::at(1),
+ SimpleValue<T>::at(2),
+ SimpleValue<T>::at(3) };
+ QList<T> myvec;
+ myvec.append(otherVec.cbegin(), otherVec.cbegin() + 3);
+ QCOMPARE(myvec.size(), 3);
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(0)
+ << SimpleValue<T>::at(1)
+ << SimpleValue<T>::at(2));
+ }
+ {
+ QList<T> emptyVec;
+ QList<T> otherEmptyVec;
+
+ emptyVec.append(otherEmptyVec);
+
+ QVERIFY(emptyVec.isEmpty());
+ QVERIFY(!emptyVec.isDetached());
+ QVERIFY(!otherEmptyVec.isDetached());
+ }
+ {
+ QList<T> myvec { SimpleValue<T>::at(0), SimpleValue<T>::at(1) };
+ QList<T> emptyVec;
+
+ myvec.append(emptyVec);
+ QVERIFY(emptyVec.isEmpty());
+ QVERIFY(!emptyVec.isDetached());
+ QCOMPARE(myvec, QList<T>({ SimpleValue<T>::at(0), SimpleValue<T>::at(1) }));
+ }
+}
+
+void tst_QList::assignEmpty() const
+{
+ // Test that the realloc branch in assign(it, it) doesn't crash.
+ using T = int;
+ QList<T> list;
+ QList<T> ref1 = list;
+ QVERIFY(list.d.needsDetach());
+ list.assign(list.begin(), list.begin());
+
+#if !defined Q_OS_QNX // QNX has problems with the empty istream_iterator
+ auto empty = std::istream_iterator<T>{};
+ list.squeeze();
+ QCOMPARE_EQ(list.capacity(), 0);
+ ref1 = list;
+ QVERIFY(list.d.needsDetach());
+ list.assign(empty, empty);
+#endif
+}
+
+template <typename T>
+void tst_QList::assign() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+ {
+ QList<T> myvec;
+ myvec.assign(2, T_FOO);
+ QVERIFY(myvec.isDetached());
+ QCOMPARE(myvec, QList<T>() << T_FOO << T_FOO);
+
+ QList<T> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ myvec.assign(3, T_BAR);
+ QCOMPARE(myvec, QList<T>() << T_BAR << T_BAR << T_BAR);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(myvecCopy.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ }
+ {
+ QList<T> myvec;
+ myvec.assign(4, T_FOO);
+ QVERIFY(myvec.isDetached());
+ QCOMPARE(myvec, QList<T>() << T_FOO << T_FOO << T_FOO << T_FOO);
+
+ QList<T> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ myvecCopy.assign(myvec.begin(), myvec.begin() + 2);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(myvecCopy.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvecCopy, QList<T>() << T_FOO << T_FOO);
+ }
+}
+
+inline namespace Scenarios {
+Q_NAMESPACE
+enum ListState {
+ UnsharedList,
+ SharedList,
+};
+Q_ENUM_NS(ListState)
+enum RelationWithPrependBuffer {
+ FitsIntoFreeSpaceAtBegin,
+ FitsFreeSpaceAtBeginExactly,
+ ExceedsFreeSpaceAtBegin,
+ FitsFreeSpaceAtBeginPlusSizeExactly,
+ FullCapacity,
+};
+Q_ENUM_NS(RelationWithPrependBuffer)
+} // namespace Scenarios
+
+void tst_QList::assignUsesPrependBuffer_data() const
+{
+ QTest::addColumn<ListState>("listState");
+ QTest::addColumn<RelationWithPrependBuffer>("relationWithPrependBuffer");
+
+ const auto sme = QMetaEnum::fromType<ListState>();
+ const auto rme = QMetaEnum::fromType<RelationWithPrependBuffer>();
+
+ for (int i = 0, s = sme.value(i); s != -1; s = sme.value(++i)) {
+ for (int j = 0, r = rme.value(j); r != -1; r = rme.value(++j)) {
+ QTest::addRow("%s-%s", sme.key(i), rme.key(j))
+ << ListState(s) << RelationWithPrependBuffer(r);
+ }
+ }
+}
+
+template <typename T>
+void tst_QList::assignUsesPrependBuffer() const
+{
+ QFETCH(const ListState, listState);
+ QFETCH(const RelationWithPrependBuffer, relationWithPrependBuffer);
+
+ const auto capBegin = [](const QList<T> &l) {
+ return l.begin() - l.d.freeSpaceAtBegin();
+ };
+ const auto capEnd = [](const QList<T> &l) {
+ return l.end() + l.d.freeSpaceAtEnd();
+ };
+
+ TST_QLIST_CHECK_LEAKS(T)
+ {
+ // Test the prepend optimization.
+ QList<T> withFreeSpaceAtBegin(16, T_FOO);
+ // try at most 100 times to create freeSpaceAtBegin():
+ for (int i = 0; i < 100 && withFreeSpaceAtBegin.d.freeSpaceAtBegin() < 2; ++i)
+ withFreeSpaceAtBegin.prepend(T_FOO);
+ QCOMPARE_GT(withFreeSpaceAtBegin.d.freeSpaceAtBegin(), 1);
+
+ auto c = [&] {
+ switch (listState) {
+ case UnsharedList: return std::move(withFreeSpaceAtBegin);
+ case SharedList: return withFreeSpaceAtBegin;
+ }
+ Q_UNREACHABLE_RETURN(withFreeSpaceAtBegin);
+ }();
+
+ const auto n = [&] () -> qsizetype {
+ switch (relationWithPrependBuffer) {
+ case FitsIntoFreeSpaceAtBegin:
+ return qsizetype(1);
+ case FitsFreeSpaceAtBeginExactly:
+ return c.d.freeSpaceAtBegin();
+ case ExceedsFreeSpaceAtBegin:
+ return c.d.freeSpaceAtBegin() + 1;
+ case FitsFreeSpaceAtBeginPlusSizeExactly:
+ return c.d.freeSpaceAtBegin() + c.size();
+ case FullCapacity:
+ return c.capacity();
+ };
+ Q_UNREACHABLE_RETURN(0);
+ }();
+
+ const auto oldCapBegin = capBegin(c);
+ const auto oldCapEnd = capEnd(c);
+
+ const std::vector v(n, T_BAR);
+ c.assign(v.begin(), v.end());
+ QCOMPARE_EQ(c.d.freeSpaceAtBegin(), 0); // we used the prepend-buffer
+ if (listState != SharedList) {
+ // check that we didn't reallocate
+ QCOMPARE_EQ(capBegin(c), oldCapBegin);
+ QCOMPARE_EQ(capEnd(c), oldCapEnd);
+ }
+ }
+}
+
+void tst_QList::appendRvalue() const
+{
+ QList<QString> v;
+ v.append("hello");
+ QString world = "world";
+ v.append(std::move(world));
+ QCOMPARE(v.front(), QString("hello"));
+ QCOMPARE(v.back(), QString("world"));
+
+ // check append rvalue to empty list
+ QList<QString> myvec;
+ QString test = "test";
+ myvec.append(std::move(test));
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.front(), QString("test"));
+}
+
+struct ConstructionCounted
+{
+ ConstructionCounted(int i) : i(i) { }
+ ConstructionCounted(ConstructionCounted &&other) noexcept
+ : i(other.i), copies(other.copies), moves(other.moves + 1)
+ {
+ // set to some easily noticeable values
+ other.i = -64;
+ other.copies = -64;
+ other.moves = -64;
+ }
+ ConstructionCounted &operator=(ConstructionCounted &&other) noexcept
+ {
+ i = other.i;
+ copies = other.copies;
+ moves = other.moves + 1;
+ // set to some easily noticeable values
+ other.i = -64;
+ other.copies = -64;
+ other.moves = -64;
+ return *this;
+ }
+ ConstructionCounted(const ConstructionCounted &other) noexcept
+ : i(other.i), copies(other.copies + 1), moves(other.moves)
+ {
+ }
+ ConstructionCounted &operator=(const ConstructionCounted &other) noexcept
+ {
+ i = other.i;
+ copies = other.copies + 1;
+ moves = other.moves;
+ return *this;
+ }
+ ~ConstructionCounted() = default;
+
+ friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs)
+ {
+ return lhs.i == rhs.i;
+ }
+
+ QString toString() { return QString::number(i); }
+
+ int i;
+ int copies = 0;
+ int moves = 0;
+};
+QT_BEGIN_NAMESPACE
+namespace QTest {
+char *toString(const ConstructionCounted &cc)
+{
+ char *str = new char[5];
+ qsnprintf(str, 4, "%d", cc.i);
+ return str;
+}
+}
+QT_END_NAMESPACE
+
+void tst_QList::appendList() const
+{
+ // By const-ref
+ {
+ QList<int> v1 = { 1, 2, 3, 4 };
+ QList<int> v2 = { 5, 6, 7, 8 };
+ v1.append(v2);
+ QCOMPARE(v2.size(), 4);
+ QCOMPARE(v1.size(), 8);
+ QList<int> expected = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ QCOMPARE(v1, expected);
+
+ QList<int> doubleExpected = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
+ // append self to self
+ v1.append(v1);
+ QCOMPARE(v1.size(), 16);
+ QCOMPARE(v1, doubleExpected);
+ v1.resize(8);
+
+ // append to self, but was shared
+ QList v1_2(v1);
+ v1.append(v1);
+ QCOMPARE(v1_2.size(), 8);
+ QCOMPARE(v1_2, expected);
+ QCOMPARE(v1.size(), 16);
+ QCOMPARE(v1, doubleExpected);
+ v1.resize(8);
+
+ // append empty
+ QList<int> v3;
+ v1.append(v3);
+
+ // append to empty
+ QList<int> v4;
+ v4.append(v1);
+ QCOMPARE(v4, expected);
+
+ v1 = { 1, 2, 3, 4 };
+ // Using operators
+ // <<
+ QList<int> v5;
+ v5 << v1 << v2;
+ QCOMPARE(v5, expected);
+
+ // +=
+ QList<int> v6;
+ v6 += v1;
+ v6 += v2;
+ QCOMPARE(v6, expected);
+
+ // +
+ QCOMPARE(v1 + v2, expected);
+ }
+ // By move
+ {
+ QList<ConstructionCounted> v1 = { 1, 2, 3, 4 };
+ // Sanity check
+ QCOMPARE(v1.at(3).moves, 0);
+ QCOMPARE(v1.at(3).copies, 1); // because of initializer list
+
+ QList<ConstructionCounted> v2 = { 5, 6, 7, 8 };
+ v1.append(std::move(v2));
+ QCOMPARE(v1.size(), 8);
+ QList<ConstructionCounted> expected = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ QCOMPARE(v1, expected);
+ QCOMPARE(v1.at(0).copies, 1);
+ QCOMPARE(v1.at(0).moves, 1);
+
+ QCOMPARE(v1.at(4).copies, 1); // was v2.at(0)
+ QCOMPARE(v1.at(4).moves, 1);
+
+ // append move from empty
+ QList<ConstructionCounted> v3;
+ v1.append(std::move(v3));
+ QCOMPARE(v1.size(), 8);
+ QCOMPARE(v1, expected);
+
+ for (qsizetype i = 0; i < v1.size(); ++i) {
+ const auto &counter = v1.at(i);
+ QCOMPARE(counter.copies, 1);
+ QCOMPARE(counter.moves, 1);
+ }
+
+ // append move to empty
+ QList<ConstructionCounted> v4;
+ v4.reserve(64);
+ v4.append(std::move(v1));
+ QCOMPARE(v4.size(), 8);
+ QCOMPARE(v4, expected);
+
+ for (qsizetype i = 0; i < v4.size(); ++i) {
+ const auto &counter = v4.at(i);
+ QCOMPARE(counter.copies, 1);
+ QCOMPARE(counter.moves, 2);
+ }
+
+ QVERIFY(v4.capacity() >= 64);
+
+ v1.swap(v4); // swap back...
+
+ // append move from shared
+ QList<ConstructionCounted> v5 = { 1, 2, 3, 4 };
+ QList<ConstructionCounted> v5_2(v5);
+ v1.append(std::move(v5_2));
+ QCOMPARE(v1.size(), 12);
+ QList<ConstructionCounted> expectedTwelve = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4 };
+ QCOMPARE(v1, expectedTwelve);
+ QCOMPARE(v5.size(), 4);
+ QList<ConstructionCounted> expectedFour = { 1, 2, 3, 4 };
+ QCOMPARE(v5, expectedFour);
+
+ QCOMPARE(v5.at(0).copies, 1); // from constructing with std::initializer_list
+ QCOMPARE(v5.at(0).moves, 0);
+
+ // Using operators
+ // <<
+ QList<ConstructionCounted> v6;
+ v6.reserve(4);
+ v6 << (QList<ConstructionCounted>() << 1 << 2);
+ v6 << (QList<ConstructionCounted>() << 3 << 4);
+ QCOMPARE(v6, expectedFour);
+ QCOMPARE(v6.at(0).copies, 1);
+ QCOMPARE(v6.at(0).moves, 3);
+
+ // +=
+ QList<ConstructionCounted> v7;
+ v7 += (QList<ConstructionCounted>() << 1 << 2);
+ v7 += (QList<ConstructionCounted>() << 3 << 4);
+ QCOMPARE(v7, expectedFour);
+
+ // +
+ QList<ConstructionCounted> v8;
+ QCOMPARE(v8 + (QList<ConstructionCounted>() << 1 << 2 << 3 << 4), expectedFour);
+ v8 = { 1, 2 };
+ QCOMPARE(v8 + (QList<ConstructionCounted>() << 3 << 4), expectedFour);
+ }
+}
+
+void tst_QList::at() const
+{
+ QList<QString> myvec;
+ myvec << "foo" << "bar" << "baz";
+
+ QVERIFY(myvec.size() == 3);
+ QCOMPARE(myvec.at(0), QLatin1String("foo"));
+ QCOMPARE(myvec.at(1), QLatin1String("bar"));
+ QCOMPARE(myvec.at(2), QLatin1String("baz"));
+
+ // append an item
+ myvec << "hello";
+ QVERIFY(myvec.size() == 4);
+ QCOMPARE(myvec.at(0), QLatin1String("foo"));
+ QCOMPARE(myvec.at(1), QLatin1String("bar"));
+ QCOMPARE(myvec.at(2), QLatin1String("baz"));
+ QCOMPARE(myvec.at(3), QLatin1String("hello"));
+
+ // remove an item
+ myvec.remove(1);
+ QVERIFY(myvec.size() == 3);
+ QCOMPARE(myvec.at(0), QLatin1String("foo"));
+ QCOMPARE(myvec.at(1), QLatin1String("baz"));
+ QCOMPARE(myvec.at(2), QLatin1String("hello"));
+}
+
+template<typename T>
+void tst_QList::capacity() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+
+ // TODO: is this guaranteed? seems a safe assumption, but I suppose preallocation of a
+ // few items isn't an entirely unforseeable possibility.
+ QVERIFY(myvec.capacity() == 0);
+ QVERIFY(!myvec.isDetached());
+
+ // test it gets a size
+ myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
+ QVERIFY(myvec.capacity() >= 3);
+
+ // make sure it grows ok
+ myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
+ QVERIFY(myvec.capacity() >= 6);
+ // let's try squeeze a bit
+ myvec.remove(3);
+ myvec.remove(3);
+ myvec.remove(3);
+ myvec.squeeze();
+ QVERIFY(myvec.capacity() >= 3);
+
+ myvec.remove(0);
+ myvec.remove(0);
+ myvec.remove(0);
+ myvec.squeeze();
+ QVERIFY(myvec.capacity() == 0);
+}
+
+template<typename T>
+void tst_QList::clear() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+ myvec.clear();
+ QVERIFY(!myvec.isDetached());
+
+ myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
+
+ const auto oldCapacity = myvec.capacity();
+ QCOMPARE(myvec.size(), 3);
+ myvec.clear();
+ QCOMPARE(myvec.size(), 0);
+ QCOMPARE(myvec.capacity(), oldCapacity);
+}
+
+void tst_QList::constData() const
+{
+ int arr[] = { 42, 43, 44 };
+ QList<int> myvec;
+ QCOMPARE(myvec.constData(), nullptr);
+ QVERIFY(!myvec.isDetached());
+
+ myvec << 42 << 43 << 44;
+
+ QCOMPARE(memcmp(myvec.constData(), reinterpret_cast<const int *>(&arr), sizeof(int) * 3), 0);
+}
+
+void tst_QList::contains() const
+{
+ QList<QString> myvec;
+
+ QVERIFY(!myvec.contains(QLatin1String("test")));
+ QVERIFY(!myvec.isDetached());
+
+ myvec << "aaa" << "bbb" << "ccc";
+
+ QVERIFY(myvec.contains(QLatin1String("aaa")));
+ QVERIFY(myvec.contains(QLatin1String("bbb")));
+ QVERIFY(myvec.contains(QLatin1String("ccc")));
+ QVERIFY(!myvec.contains(QLatin1String("I don't exist")));
+
+ // add it and make sure it does :)
+ myvec.append(QLatin1String("I don't exist"));
+ QVERIFY(myvec.contains(QLatin1String("I don't exist")));
+}
+
+template<typename T>
+void tst_QList::count() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // total size
+ {
+ // zero size
+ QList<T> myvec;
+ QVERIFY(myvec.size() == 0);
+ QVERIFY(!myvec.isDetached());
+
+ // grow
+ myvec.append(SimpleValue<T>::at(0));
+ QVERIFY(myvec.size() == 1);
+ myvec.append(SimpleValue<T>::at(1));
+ QVERIFY(myvec.size() == 2);
+
+ // shrink
+ myvec.remove(0);
+ QVERIFY(myvec.size() == 1);
+ myvec.remove(0);
+ QVERIFY(myvec.size() == 0);
+ }
+
+ // count of items
+ {
+ QList<T> myvec;
+ QCOMPARE(myvec.count(SimpleValue<T>::at(0)), 0);
+ QVERIFY(!myvec.isDetached());
+
+ myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
+
+ // initial tests
+ QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
+ QVERIFY(myvec.count(SimpleValue<T>::at(3)) == 0);
+
+ // grow
+ myvec.append(SimpleValue<T>::at(0));
+ QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 2);
+
+ // shrink
+ myvec.remove(0);
+ QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
+ }
+}
+
+void tst_QList::cpp17ctad() const
+{
+#define QVERIFY_IS_VECTOR_OF(obj, Type) \
+ QVERIFY2((std::is_same<decltype(obj), QList<Type>>::value), \
+ QMetaType::fromType<decltype(obj)::value_type>().name())
+#define CHECK(Type, One, Two, Three) \
+ do { \
+ const Type v[] = {One, Two, Three}; \
+ QList v1 = {One, Two, Three}; \
+ QVERIFY_IS_VECTOR_OF(v1, Type); \
+ QList v2(v1.begin(), v1.end()); \
+ QVERIFY_IS_VECTOR_OF(v2, Type); \
+ QList v3(std::begin(v), std::end(v)); \
+ QVERIFY_IS_VECTOR_OF(v3, Type); \
+ } while (false) \
+ /*end*/
+ CHECK(int, 1, 2, 3);
+ CHECK(double, 1.0, 2.0, 3.0);
+ CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
+#undef QVERIFY_IS_VECTOR_OF
+#undef CHECK
+}
+
+void tst_QList::data() const
+{
+ QList<int> myvec;
+ QCOMPARE(myvec.data(), nullptr);
+
+ myvec << 42 << 43 << 44;
+
+ // make sure it starts off ok
+ QCOMPARE(*(myvec.data() + 1), 43);
+
+ // alter it
+ *(myvec.data() + 1) = 69;
+
+ // check it altered
+ QCOMPARE(*(myvec.data() + 1), 69);
+
+ int arr[] = { 42, 69, 44 };
+ QCOMPARE(memcmp(myvec.data(), reinterpret_cast<int *>(&arr), sizeof(int) * 3), 0);
+
+ const QList<int> constVec = myvec;
+ QCOMPARE(memcmp(constVec.data(), reinterpret_cast<const int *>(&arr), sizeof(int) * 3), 0);
+ QVERIFY(!constVec.isDetached()); // const data() does not detach()
+}
+
+template<typename T>
+void tst_QList::empty() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+
+ // starts empty
+ QVERIFY(myvec.empty());
+ QVERIFY(!myvec.isDetached());
+
+ // not empty
+ myvec.append(SimpleValue<T>::at(2));
+ QVERIFY(!myvec.empty());
+
+ // empty again
+ myvec.remove(0);
+ QVERIFY(myvec.empty());
+}
+
+void tst_QList::endsWith() const
+{
+ QList<int> myvec;
+
+ // empty vector
+ QVERIFY(!myvec.endsWith(1));
+
+ // add the one, should work
+ myvec.append(1);
+ QVERIFY(myvec.endsWith(1));
+
+ // add something else, fails now
+ myvec.append(3);
+ QVERIFY(!myvec.endsWith(1));
+
+ // remove it again :)
+ myvec.remove(1);
+ QVERIFY(myvec.endsWith(1));
+}
+
+template<typename T>
+void tst_QList::eraseEmpty() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> v;
+ v.erase(v.begin(), v.end());
+ QCOMPARE(v.size(), 0);
+}
+
+template<typename T>
+void tst_QList::eraseEmptyReserved() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> v;
+ v.reserve(10);
+ v.erase(v.begin(), v.end());
+ QCOMPARE(v.size(), 0);
+}
+
+template<typename T>
+struct SharedVectorChecker
+{
+ SharedVectorChecker(const QList<T> &original, bool doCopyVector)
+ : originalSize(-1),
+ copy(0)
+ {
+ if (doCopyVector) {
+ originalSize = original.size();
+ copy = new QList<T>(original);
+ // this is unlikely to fail, but if the check in the destructor fails it's good to know that
+ // we were still alright here.
+ QCOMPARE(originalSize, copy->size());
+ }
+ }
+
+ ~SharedVectorChecker()
+ {
+ if (copy)
+ QCOMPARE(copy->size(), originalSize);
+ delete copy;
+ }
+
+ int originalSize;
+ QList<T> *copy;
+};
+
+template<typename T>
+void tst_QList::erase(bool shared) const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // note: remove() is actually more efficient, and more dangerous, because it uses the
+ // non-detaching begin() / end() internally. you can also use constBegin() and constEnd() with
+ // erase(), but only using reinterpret_cast... because both iterator types are really just
+ // pointers. so we use a mix of erase() and remove() to cover more cases.
+ {
+ QList<T> v = SimpleValue<T>::vector(12);
+ SharedVectorChecker<T> svc(v, shared);
+ v.erase(v.begin());
+ QCOMPARE(v.size(), 11);
+ for (int i = 0; i < 11; i++)
+ QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
+ v.erase(v.begin(), v.end());
+ QCOMPARE(v.size(), 0);
+ if (shared)
+ QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
+ }
+ {
+ QList<T> v = SimpleValue<T>::vector(12);
+ SharedVectorChecker<T> svc(v, shared);
+ v.remove(1);
+ QCOMPARE(v.size(), 11);
+ QCOMPARE(v.at(0), SimpleValue<T>::at(0));
+ for (int i = 1; i < 11; i++)
+ QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
+ v.erase(v.begin() + 1, v.end());
+ QCOMPARE(v.size(), 1);
+ QCOMPARE(v.at(0), SimpleValue<T>::at(0));
+ if (shared)
+ QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
+ }
+ {
+ QList<T> v = SimpleValue<T>::vector(12);
+ SharedVectorChecker<T> svc(v, shared);
+ v.erase(v.begin(), v.end() - 1);
+ QCOMPARE(v.size(), 1);
+ QCOMPARE(v.at(0), SimpleValue<T>::at(11));
+ if (shared)
+ QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
+ }
+ {
+ QList<T> v = SimpleValue<T>::vector(12);
+ SharedVectorChecker<T> svc(v, shared);
+ v.remove(5);
+ QCOMPARE(v.size(), 11);
+ for (int i = 0; i < 5; i++)
+ QCOMPARE(v.at(i), SimpleValue<T>::at(i));
+ for (int i = 5; i < 11; i++)
+ QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
+ v.erase(v.begin() + 1, v.end() - 1);
+ QCOMPARE(v.at(0), SimpleValue<T>::at(0));
+ QCOMPARE(v.at(1), SimpleValue<T>::at(11));
+ QCOMPARE(v.size(), 2);
+ if (shared)
+ QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
+ }
+}
+
+template<typename T>
+void tst_QList::eraseReserved() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ QList<T> v(12);
+ v.reserve(16);
+ v.erase(v.begin());
+ QCOMPARE(v.size(), 11);
+ v.erase(v.begin(), v.end());
+ QCOMPARE(v.size(), 0);
+ }
+ {
+ QList<T> v(12);
+ v.reserve(16);
+ v.erase(v.begin() + 1);
+ QCOMPARE(v.size(), 11);
+ v.erase(v.begin() + 1, v.end());
+ QCOMPARE(v.size(), 1);
+ }
+ {
+ QList<T> v(12);
+ v.reserve(16);
+ v.erase(v.begin(), v.end() - 1);
+ QCOMPARE(v.size(), 1);
+ }
+ {
+ QList<T> v(12);
+ v.reserve(16);
+ v.erase(v.begin() + 5);
+ QCOMPARE(v.size(), 11);
+ v.erase(v.begin() + 1, v.end() - 1);
+ QCOMPARE(v.size(), 2);
+ }
+}
+
+template<typename T>
+void tst_QList::fill() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+
+ // fill an empty list - it should resize
+ myvec.fill(SimpleValue<T>::at(1), 2);
+ QCOMPARE(myvec, QList<T>({ SimpleValue<T>::at(1), SimpleValue<T>::at(1) }));
+
+ // resize
+ myvec.resize(5);
+ myvec.fill(SimpleValue<T>::at(1));
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
+ << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
+ << SimpleValue<T>::at(1));
+
+ // make sure it can resize itself too
+ myvec.fill(SimpleValue<T>::at(2), 10);
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+ << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+ << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+ << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
+ << SimpleValue<T>::at(2) << SimpleValue<T>::at(2));
+
+ // make sure it can resize to smaller size as well
+ myvec.fill(SimpleValue<T>::at(3), 2);
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(3) << SimpleValue<T>::at(3));
+}
+
+template<typename T>
+void tst_QList::fillDetach() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // detaches to the same size
+ {
+ QList<T> original = { SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) };
+ QList<T> copy = original;
+ copy.fill(SimpleValue<T>::at(2));
+
+ QCOMPARE(original,
+ QList<T>({ SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) }));
+ QCOMPARE(copy,
+ QList<T>({ SimpleValue<T>::at(2), SimpleValue<T>::at(2), SimpleValue<T>::at(2) }));
+ }
+
+ // detaches and grows in size
+ {
+ QList<T> original = { SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) };
+ QList<T> copy = original;
+ copy.fill(SimpleValue<T>::at(2), 5);
+
+ QCOMPARE(original,
+ QList<T>({ SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) }));
+ QCOMPARE(copy,
+ QList<T>({ SimpleValue<T>::at(2), SimpleValue<T>::at(2), SimpleValue<T>::at(2),
+ SimpleValue<T>::at(2), SimpleValue<T>::at(2) }));
+ }
+
+ // detaches and shrinks in size
+ {
+ QList<T> original = { SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) };
+ QList<T> copy = original;
+ copy.fill(SimpleValue<T>::at(2), 1);
+
+ QCOMPARE(original,
+ QList<T>({ SimpleValue<T>::at(1), SimpleValue<T>::at(1), SimpleValue<T>::at(1) }));
+ QCOMPARE(copy, QList<T>({ SimpleValue<T>::at(2) }));
+ }
+}
+
+void tst_QList::first() const
+{
+ QList<int> myvec;
+ myvec << 69 << 42 << 3;
+
+ // test it starts ok
+ QCOMPARE(myvec.first(), 69);
+ QCOMPARE(myvec.constFirst(), 69);
+
+ // test removal changes
+ myvec.remove(0);
+ QCOMPARE(myvec.first(), 42);
+ QCOMPARE(myvec.constFirst(), 42);
+
+ // test prepend changes
+ myvec.prepend(23);
+ QCOMPARE(myvec.first(), 23);
+ QCOMPARE(myvec.constFirst(), 23);
+
+
+ QCOMPARE(QList<int>().first(0), QList<int>());
+ QCOMPARE(myvec.first(0), QList<int>());
+ QCOMPARE(myvec.first(1), (QList<int>{23}));
+ QCOMPARE(myvec.first(2), (QList<int>{23, 42}));
+ QCOMPARE(myvec.first(3), myvec);
+}
+
+void tst_QList::constFirst() const
+{
+ QList<int> myvec;
+ myvec << 69 << 42 << 3;
+
+ // test it starts ok
+ QCOMPARE(myvec.constFirst(), 69);
+ QVERIFY(myvec.isDetached());
+
+ QList<int> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constFirst(), 69);
+ QCOMPARE(myvecCopy.constFirst(), 69);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ // test removal changes
+ myvec.remove(0);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QCOMPARE(myvec.constFirst(), 42);
+ QCOMPARE(myvecCopy.constFirst(), 69);
+
+ myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constFirst(), 42);
+ QCOMPARE(myvecCopy.constFirst(), 42);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ // test prepend changes
+ myvec.prepend(23);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QCOMPARE(myvec.constFirst(), 23);
+ QCOMPARE(myvecCopy.constFirst(), 42);
+
+ myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constFirst(), 23);
+ QCOMPARE(myvecCopy.constFirst(), 23);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+}
+
+
+template<typename T>
+void tst_QList::fromList() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> list;
+ list << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3);
+
+ QList<T> myvec;
+ myvec = QList<T>::fromList(list);
+
+ // test it worked ok
+ QCOMPARE(myvec, QList<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
+ QCOMPARE(list, QList<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+void tst_QList::fromStdVector() const
+{
+ // stl = :(
+ std::vector<QString> svec;
+ svec.push_back(QLatin1String("aaa"));
+ svec.push_back(QLatin1String("bbb"));
+ svec.push_back(QLatin1String("ninjas"));
+ svec.push_back(QLatin1String("pirates"));
+ QList<QString> myvec = QList<QString>::fromStdVector(svec);
+
+ // test it converts ok
+ QCOMPARE(myvec, QList<QString>() << "aaa" << "bbb" << "ninjas" << "pirates");
+}
+#endif
+
+void tst_QList::indexOf() const
+{
+ QList<QString> myvec;
+
+ QCOMPARE(myvec.indexOf("A"), -1);
+ QCOMPARE(myvec.indexOf("A", 5), -1);
+ QVERIFY(!myvec.isDetached());
+
+ myvec << "A" << "B" << "C" << "B" << "A";
+
+ QVERIFY(myvec.indexOf("B") == 1);
+ QVERIFY(myvec.indexOf("B", 1) == 1);
+ QVERIFY(myvec.indexOf("B", 2) == 3);
+ QVERIFY(myvec.indexOf("X") == -1);
+ QVERIFY(myvec.indexOf("X", 2) == -1);
+
+ // add an X
+ myvec << "X";
+ QVERIFY(myvec.indexOf("X") == 5);
+ QVERIFY(myvec.indexOf("X", 5) == 5);
+ QVERIFY(myvec.indexOf("X", 6) == -1);
+
+ // remove first A
+ myvec.remove(0);
+ QVERIFY(myvec.indexOf("A") == 3);
+ QVERIFY(myvec.indexOf("A", 3) == 3);
+ QVERIFY(myvec.indexOf("A", 4) == -1);
+}
+
+template <typename T>
+void tst_QList::insert() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+ const T
+ tA = SimpleValue<T>::at(0),
+ tB = SimpleValue<T>::at(1),
+ tC = SimpleValue<T>::at(2),
+ tX = SimpleValue<T>::at(3),
+ tZ = SimpleValue<T>::at(4),
+ tT = SimpleValue<T>::at(5),
+ ti = SimpleValue<T>::at(6);
+ myvec << tA << tB << tC;
+ QList<T> myvec2 = myvec;
+
+ // first position
+ QCOMPARE(myvec.at(0), tA);
+ myvec.insert(0, tX);
+ QCOMPARE(myvec.at(0), tX);
+ QCOMPARE(myvec.at(1), tA);
+
+ QCOMPARE(myvec2.at(0), tA);
+ myvec2.insert(myvec2.begin(), tX);
+ QCOMPARE(myvec2.at(0), tX);
+ QCOMPARE(myvec2.at(1), tA);
+
+ // middle
+ myvec.insert(1, tZ);
+ QCOMPARE(myvec.at(0), tX);
+ QCOMPARE(myvec.at(1), tZ);
+ QCOMPARE(myvec.at(2), tA);
+
+ myvec2.insert(myvec2.begin() + 1, tZ);
+ QCOMPARE(myvec2.at(0), tX);
+ QCOMPARE(myvec2.at(1), tZ);
+ QCOMPARE(myvec2.at(2), tA);
+
+ // end
+ myvec.insert(5, tT);
+ QCOMPARE(myvec.at(5), tT);
+ QCOMPARE(myvec.at(4), tC);
+
+ myvec2.insert(myvec2.end(), tT);
+ QCOMPARE(myvec2.at(5), tT);
+ QCOMPARE(myvec2.at(4), tC);
+
+ // insert a lot of garbage in the middle
+ myvec.insert(2, 2, ti);
+ QCOMPARE(myvec, QList<T>() << tX << tZ << ti << ti
+ << tA << tB << tC << tT);
+
+ myvec2.insert(myvec2.begin() + 2, 2, ti);
+ QCOMPARE(myvec2, myvec);
+
+ // insert from references to the same container:
+ myvec.insert(0, 1, myvec[5]); // inserts tB
+ myvec2.insert(0, 1, myvec2[5]); // inserts tB
+ QCOMPARE(myvec, QList<T>() << tB << tX << tZ << ti << ti
+ << tA << tB << tC << tT);
+ QCOMPARE(myvec2, myvec);
+
+ myvec.insert(0, 1, const_cast<const QList<T>&>(myvec)[0]); // inserts tB
+ myvec2.insert(0, 1, const_cast<const QList<T>&>(myvec2)[0]); // inserts tB
+ QCOMPARE(myvec, QList<T>() << tB << tB << tX << tZ << ti << ti
+ << tA << tB << tC << tT);
+ QCOMPARE(myvec2, myvec);
+
+ // Different insert() into empty list overloads
+ {
+ QList<T> myvec;
+ auto it = myvec.insert(0, tA);
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.front(), tA);
+ QCOMPARE(it, myvec.begin());
+ }
+ {
+ QList<T> myvec;
+ auto it = myvec.insert(0, 3, tX);
+ QCOMPARE(myvec.size(), 3);
+ QCOMPARE(myvec, QList<T>({ tX, tX, tX }));
+ QCOMPARE(it, myvec.begin());
+ }
+ {
+ QList<T> myvec;
+ auto it = myvec.insert(myvec.cbegin(), tA);
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.front(), tA);
+ QCOMPARE(it, myvec.begin());
+ }
+ {
+ QList<T> myvec;
+ auto it = myvec.insert(myvec.cbegin(), 3, tX);
+ QCOMPARE(myvec.size(), 3);
+ QCOMPARE(myvec, QList<T>({ tX, tX, tX }));
+ QCOMPARE(it, myvec.begin());
+ }
+ {
+ QList<QString> myvec;
+ QString test = "test";
+ auto it = myvec.insert(0, std::move(test));
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.front(), u"test");
+ QCOMPARE(it, myvec.begin());
+ }
+ {
+ QList<QString> myvec;
+ QString test = "test";
+ auto it = myvec.insert(myvec.cbegin(), std::move(test));
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.front(), u"test");
+ QCOMPARE(it, myvec.begin());
+ }
+}
+
+void tst_QList::insertZeroCount_data()
+{
+ QTest::addColumn<int>("pos");
+ QTest::newRow("0") << 0;
+ QTest::newRow("1") << 1;
+}
+
+void tst_QList::insertZeroCount() const
+{
+ QFETCH(int, pos);
+ QList<int> x;
+ x << 0 << 0;
+ x.insert(pos, 0, 1);
+ QCOMPARE(x[pos], 0);
+ QList<int> y;
+ y = x;
+ y.insert(pos, 0, 2);
+ QCOMPARE(y[pos], 0);
+}
+
+void tst_QList::isEmpty() const
+{
+ QList<QString> myvec;
+
+ // starts ok
+ QVERIFY(myvec.isEmpty());
+ QVERIFY(!myvec.isDetached());
+
+ // not empty now
+ myvec.append(QLatin1String("hello there"));
+ QVERIFY(!myvec.isEmpty());
+
+ // empty again
+ myvec.remove(0);
+ QVERIFY(myvec.isEmpty());
+}
+
+void tst_QList::last() const
+{
+ QList<QString> myvec;
+ myvec << "A" << "B" << "C";
+
+ // test starts ok
+ QCOMPARE(myvec.last(), QLatin1String("C"));
+ QCOMPARE(myvec.constLast(), QLatin1String("C"));
+
+ // test it changes ok
+ myvec.append(QLatin1String("X"));
+ QCOMPARE(myvec.last(), QLatin1String("X"));
+ QCOMPARE(myvec.constLast(), QLatin1String("X"));
+
+ // and remove again
+ myvec.remove(3);
+ QCOMPARE(myvec.last(), QLatin1String("C"));
+ QCOMPARE(myvec.constLast(), QLatin1String("C"));
+
+ QCOMPARE(QList<QString>().last(0), QList<QString>());
+ QCOMPARE(myvec.last(0), QList<QString>());
+ QCOMPARE(myvec.last(1), (QList<QString>{QLatin1String("C")}));
+ QCOMPARE(myvec.last(2), (QList<QString>{QLatin1String("B"), QLatin1String("C")}));
+ QCOMPARE(myvec.last(3), myvec);
+}
+
+void tst_QList::constLast() const
+{
+ QList<int> myvec;
+ myvec << 69 << 42 << 3;
+
+ // test it starts ok
+ QCOMPARE(myvec.constLast(), 3);
+ QVERIFY(myvec.isDetached());
+
+ QList<int> myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constLast(), 3);
+ QCOMPARE(myvecCopy.constLast(), 3);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ // test removal changes
+ myvec.removeLast();
+ QVERIFY(myvec.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QCOMPARE(myvec.constLast(), 42);
+ QCOMPARE(myvecCopy.constLast(), 3);
+
+ myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constLast(), 42);
+ QCOMPARE(myvecCopy.constLast(), 42);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ // test prepend changes
+ myvec.append(23);
+ QVERIFY(myvec.isDetached());
+ QVERIFY(!myvec.isSharedWith(myvecCopy));
+ QCOMPARE(myvec.constLast(), 23);
+ QCOMPARE(myvecCopy.constLast(), 42);
+
+ myvecCopy = myvec;
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+
+ QCOMPARE(myvec.constLast(), 23);
+ QCOMPARE(myvecCopy.constLast(), 23);
+
+ QVERIFY(!myvec.isDetached());
+ QVERIFY(!myvecCopy.isDetached());
+ QVERIFY(myvec.isSharedWith(myvecCopy));
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+}
+
+void tst_QList::lastIndexOf() const
+{
+ QList<QString> myvec;
+
+ QCOMPARE(myvec.lastIndexOf("A"), -1);
+ QCOMPARE(myvec.lastIndexOf("A", 5), -1);
+ QVERIFY(!myvec.isDetached());
+
+ myvec << "A" << "B" << "C" << "B" << "A";
+
+ QVERIFY(myvec.lastIndexOf("B") == 3);
+ QVERIFY(myvec.lastIndexOf("B", 2) == 1);
+ QVERIFY(myvec.lastIndexOf("X") == -1);
+ QVERIFY(myvec.lastIndexOf("X", 2) == -1);
+
+ // add an X
+ myvec << "X";
+ QVERIFY(myvec.lastIndexOf("X") == 5);
+ QVERIFY(myvec.lastIndexOf("X", 5) == 5);
+ QVERIFY(myvec.lastIndexOf("X", 3) == -1);
+
+ // remove first A
+ myvec.remove(0);
+ QVERIFY(myvec.lastIndexOf("A") == 3);
+ QVERIFY(myvec.lastIndexOf("A", 3) == 3);
+ QVERIFY(myvec.lastIndexOf("A", 2) == -1);
+}
+
+void tst_QList::mid() const
+{
+ QList<QString> list;
+
+ QCOMPARE(list.mid(4, 2), QList<QString>());
+ QCOMPARE(list.mid(0, 3), QList<QString>());
+ QCOMPARE(list.mid(-2, 3), QList<QString>());
+ QVERIFY(!list.isDetached());
+
+ list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty";
+
+ QCOMPARE(list.mid(3, 3), QList<QString>() << "bak" << "buck" << "hello");
+ QCOMPARE(list.mid(6, 10), QList<QString>() << "kitty");
+ QCOMPARE(list.mid(-1, 20), list);
+ QCOMPARE(list.mid(4), QList<QString>() << "buck" << "hello" << "kitty");
+}
+
+void tst_QList::sliced() const
+{
+ QList<QString> list;
+ list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty";
+
+ QCOMPARE(QList<QString>().sliced(0), QList<QString>());
+ QCOMPARE(QList<QString>().sliced(0, 0), QList<QString>());
+ QCOMPARE(list.sliced(3, 3), QList<QString>() << "bak" << "buck" << "hello");
+ QCOMPARE(list.sliced(3), QList<QString>() << "bak" << "buck" << "hello" << "kitty");
+ QCOMPARE(list.sliced(6, 1), QList<QString>() << "kitty");
+ QCOMPARE(list.sliced(6), QList<QString>() << "kitty");
+ QCOMPARE(list.sliced(0, list.size()), list);
+ QCOMPARE(list.sliced(0), list);
+ QCOMPARE(list.sliced(4), QList<QString>() << "buck" << "hello" << "kitty");
+}
+
+template <typename T>
+void tst_QList::qhash() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> l1, l2;
+ QCOMPARE(qHash(l1), qHash(l2));
+ l1 << SimpleValue<T>::at(0);
+ l2 << SimpleValue<T>::at(0);
+ QCOMPARE(qHash(l1), qHash(l2));
+}
+
+template <typename T>
+void tst_QList::move() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // move an item
+ list.move(0, list.size() - 1);
+ QCOMPARE(list, QList<T>() << T_BAR << T_BAZ << T_FOO);
+
+ // move it back
+ list.move(list.size() - 1, 0);
+ QCOMPARE(list, QList<T>() << T_FOO << T_BAR << T_BAZ);
+
+ // move an item in the middle
+ list.move(1, 0);
+ QCOMPARE(list, QList<T>() << T_BAR << T_FOO << T_BAZ);
+}
+
+template<typename T>
+void tst_QList::prepend() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+
+ T val1 = SimpleValue<T>::at(0);
+ T val2 = SimpleValue<T>::at(1);
+ T val3 = SimpleValue<T>::at(2);
+ T val4 = SimpleValue<T>::at(3);
+ T val5 = SimpleValue<T>::at(4);
+
+ // prepend to default-constructed empty list
+ myvec.prepend(val1);
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.at(0), val1);
+ myvec.clear();
+
+ myvec << val1 << val2 << val3;
+
+ // starts ok
+ QVERIFY(myvec.size() == 3);
+ QCOMPARE(myvec.at(0), val1);
+
+ // add something
+ myvec.prepend(val4);
+ QCOMPARE(myvec.at(0), val4);
+ QCOMPARE(myvec.at(1), val1);
+ QVERIFY(myvec.size() == 4);
+
+ // something else
+ myvec.prepend(val5);
+ QCOMPARE(myvec.at(0), val5);
+ QCOMPARE(myvec.at(1), val4);
+ QCOMPARE(myvec.at(2), val1);
+ QVERIFY(myvec.size() == 5);
+
+ // clear and prepend to an empty vector
+ myvec.clear();
+ QVERIFY(myvec.size() == 0);
+ myvec.prepend(val5);
+ QVERIFY(myvec.size() == 1);
+ QCOMPARE(myvec.at(0), val5);
+}
+
+void tst_QList::prependRvalue() const
+{
+ QList<QString> myvec;
+
+ QString hello = "hello";
+ QString world = "world";
+
+ myvec.prepend(std::move(world));
+ QCOMPARE(myvec.size(), 1);
+
+ myvec.prepend(std::move(hello));
+ QCOMPARE(myvec.size(), 2);
+ QCOMPARE(myvec, QList<QString>({ "hello", "world" }));
+}
+
+void tst_QList::removeAllWithAlias() const
+{
+ QList<QString> strings;
+ strings << "One" << "Two" << "Three" << "One" /* must be distinct, but equal */;
+ QCOMPARE(strings.removeAll(strings.front()), 2); // will trigger asan/ubsan
+}
+
+template<typename T>
+void tst_QList::remove() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> myvec;
+ T val1 = SimpleValue<T>::at(1);
+ T val2 = SimpleValue<T>::at(2);
+ T val3 = SimpleValue<T>::at(3);
+ T val4 = SimpleValue<T>::at(4);
+ T val5 = SimpleValue<T>::at(5);
+
+ // some operations on empty list
+ QVERIFY(!myvec.removeOne(val1));
+ QCOMPARE(myvec.removeAll(val2), 0);
+ auto count = myvec.removeIf([](const T&) { return true; });
+ QCOMPARE(count, 0);
+
+ myvec << val1 << val2 << val3 << val4;
+ myvec << val1 << val2 << val3 << val4;
+ myvec << val1 << val2 << val3 << val4;
+ // remove by index
+ myvec.remove(1);
+ QCOMPARE(myvec, QList<T>({ val1, val3, val4, val1, val2, val3, val4, val1, val2, val3, val4 }));
+ myvec.removeAt(6);
+ QCOMPARE(myvec, QList<T>({ val1, val3, val4, val1, val2, val3, val1, val2, val3, val4 }));
+
+ // removeOne()
+ QVERIFY(!myvec.removeOne(val5));
+ QVERIFY(myvec.removeOne(val2));
+ QCOMPARE(myvec, QList<T>({ val1, val3, val4, val1, val3, val1, val2, val3, val4 }));
+
+ QList<T> myvecCopy = myvec;
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+ // removeAll()
+ QCOMPARE(myvec.removeAll(val5), 0);
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvec.removeAll(val1), 3);
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvec, QList<T>({ val3, val4, val3, val2, val3, val4 }));
+ QCOMPARE(myvecCopy, QList<T>({ val1, val3, val4, val1, val3, val1, val2, val3, val4 }));
+ myvecCopy = myvec;
+ QVERIFY(myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvec.removeAll(val2), 1);
+ QVERIFY(!myvecCopy.isSharedWith(myvec));
+ QCOMPARE(myvec, QList<T>({ val3, val4, val3, val3, val4 }));
+ QCOMPARE(myvecCopy, QList<T>({ val3, val4, val3, val2, val3, val4 }));
+
+ // removeIf
+ count = myvec.removeIf([&val4](const T &val) { return val == val4; });
+ QCOMPARE(count, 2);
+ QCOMPARE(myvec, QList<T>({ val3, val3, val3 }));
+
+ // remove rest
+ myvec.remove(0, 3);
+ QCOMPARE(myvec, QList<T>());
+}
+
+struct RemoveLastTestClass
+{
+ RemoveLastTestClass() { other = 0; deleted = false; }
+ RemoveLastTestClass *other;
+ bool deleted;
+ ~RemoveLastTestClass()
+ {
+ deleted = true;
+ if (other)
+ other->other = 0;
+ }
+};
+
+void tst_QList::removeFirstLast() const
+{
+ // pop_pack - pop_front
+ QList<int> t, t2;
+ t.append(1);
+ t.append(2);
+ t.append(3);
+ t.append(4);
+ t2 = t;
+ t.pop_front();
+ QCOMPARE(t.size(), 3);
+ QCOMPARE(t.at(0), 2);
+ t.pop_back();
+ QCOMPARE(t.size(), 2);
+ QCOMPARE(t.at(0), 2);
+ QCOMPARE(t.at(1), 3);
+
+ // takefirst - takeLast
+ int n1 = t2.takeLast();
+ QCOMPARE(t2.size(), 3);
+ QCOMPARE(n1, 4);
+ QCOMPARE(t2.at(0), 1);
+ QCOMPARE(t2.at(2), 3);
+ n1 = t2.takeFirst();
+ QCOMPARE(t2.size(), 2);
+ QCOMPARE(n1, 1);
+ QCOMPARE(t2.at(0), 2);
+ QCOMPARE(t2.at(1), 3);
+
+ // remove first
+ QList<int> x, y;
+ x.append(1);
+ x.append(2);
+ y = x;
+ x.removeFirst();
+ QCOMPARE(x.size(), 1);
+ QCOMPARE(y.size(), 2);
+ QCOMPARE(x.at(0), 2);
+
+ // remove Last
+ QList<RemoveLastTestClass> v;
+ v.resize(2);
+ v[0].other = &(v[1]);
+ v[1].other = &(v[0]);
+ // Check dtor - complex type
+ QVERIFY(v.at(0).other != 0);
+ v.removeLast();
+ QVERIFY(v.at(0).other == 0);
+ QCOMPARE(v.at(0).deleted, false);
+ // check iterator
+ int count = 0;
+ for (QList<RemoveLastTestClass>::const_iterator i = v.constBegin(); i != v.constEnd(); ++i) {
+ ++count;
+ QVERIFY(i->other == 0);
+ QCOMPARE(i->deleted, false);
+ }
+ // Check size
+ QCOMPARE(count, 1);
+ QCOMPARE(v.size(), 1);
+ v.removeLast();
+ QCOMPARE(v.size(), 0);
+ // Check if we do correct realloc
+ QList<int> v2, v3;
+ v2.append(1);
+ v2.append(2);
+ v3 = v2; // shared
+ v2.removeLast();
+ QCOMPARE(v2.size(), 1);
+ QCOMPARE(v3.size(), 2);
+ QCOMPARE(v2.at(0), 1);
+ QCOMPARE(v3.at(0), 1);
+ QCOMPARE(v3.at(1), 2);
+
+ // Remove last with shared
+ QList<int> z1, z2;
+ z1.append(9);
+ z2 = z1;
+ z1.removeLast();
+ QCOMPARE(z1.size(), 0);
+ QCOMPARE(z2.size(), 1);
+ QCOMPARE(z2.at(0), 9);
+}
+
+
+void tst_QList::resizePOD_data() const
+{
+ QTest::addColumn<QList<int> >("vector");
+ QTest::addColumn<int>("size");
+
+ QVERIFY(!QTypeInfo<int>::isComplex);
+ QVERIFY(QTypeInfo<int>::isRelocatable);
+
+ QList<int> null;
+ QList<int> empty(0, 5);
+ QList<int> emptyReserved;
+ QList<int> nonEmpty;
+ QList<int> nonEmptyReserved;
+
+ emptyReserved.reserve(10);
+ nonEmptyReserved.reserve(15);
+ nonEmpty << 0 << 1 << 2 << 3 << 4;
+ nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6;
+ QVERIFY(emptyReserved.capacity() >= 10);
+ QVERIFY(nonEmptyReserved.capacity() >= 15);
+
+ QTest::newRow("null") << null << 10;
+ QTest::newRow("null and 0 size") << null << 0;
+ QTest::newRow("empty") << empty << 10;
+ QTest::newRow("empty and 0 size") << empty << 0;
+ QTest::newRow("emptyReserved") << emptyReserved << 10;
+ QTest::newRow("nonEmpty") << nonEmpty << 10;
+ QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
+}
+
+void tst_QList::resizePOD() const
+{
+ QFETCH(QList<int>, vector);
+ QFETCH(int, size);
+
+ const int oldSize = vector.size();
+
+ vector.resize(size);
+ QCOMPARE(vector.size(), size);
+ QVERIFY(vector.capacity() >= size);
+ if (vector.isEmpty())
+ QVERIFY(!vector.isDetached());
+
+ for (int i = oldSize; i < size; ++i)
+ QVERIFY(vector[i] == 0); // check initialization
+
+ const int capacity = vector.capacity();
+
+ vector.clear();
+ QCOMPARE(vector.size(), 0);
+ QVERIFY(vector.capacity() <= capacity);
+}
+
+void tst_QList::resizeComplexMovable_data() const
+{
+ QTest::addColumn<QList<Movable> >("vector");
+ QTest::addColumn<int>("size");
+
+ QVERIFY(QTypeInfo<Movable>::isComplex);
+ QVERIFY(QTypeInfo<Movable>::isRelocatable);
+
+ QList<Movable> null;
+ QList<Movable> empty(0, 'Q');
+ QList<Movable> emptyReserved;
+ QList<Movable> nonEmpty;
+ QList<Movable> nonEmptyReserved;
+
+ emptyReserved.reserve(10);
+ nonEmptyReserved.reserve(15);
+ nonEmpty << '0' << '1' << '2' << '3' << '4';
+ nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
+ QVERIFY(emptyReserved.capacity() >= 10);
+ QVERIFY(nonEmptyReserved.capacity() >= 15);
+
+ QTest::newRow("null") << null << 10;
+ QTest::newRow("null and 0 size") << null << 0;
+ QTest::newRow("empty") << empty << 10;
+ QTest::newRow("empty and 0 size") << empty << 0;
+ QTest::newRow("emptyReserved") << emptyReserved << 10;
+ QTest::newRow("nonEmpty") << nonEmpty << 10;
+ QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
+}
+
+void tst_QList::resizeComplexMovable() const
+{
+ const int items = Movable::counter.loadAcquire();
+ {
+ QFETCH(QList<Movable>, vector);
+ QFETCH(int, size);
+
+ const int oldSize = vector.size();
+
+ vector.resize(size);
+ QCOMPARE(vector.size(), size);
+ QVERIFY(vector.capacity() >= size);
+ if (vector.isEmpty())
+ QVERIFY(!vector.isDetached());
+ for (int i = oldSize; i < size; ++i)
+ QVERIFY(vector[i] == 'j'); // check initialization
+
+ const int capacity = vector.capacity();
+
+ vector.resize(0);
+ QCOMPARE(vector.size(), 0);
+ QVERIFY(vector.capacity() <= capacity);
+ }
+ QCOMPARE(items, Movable::counter.loadAcquire());
+}
+
+void tst_QList::resizeComplex_data() const
+{
+ QTest::addColumn<QList<Custom> >("vector");
+ QTest::addColumn<int>("size");
+
+ QVERIFY(QTypeInfo<Custom>::isComplex);
+ QVERIFY(!QTypeInfo<Custom>::isRelocatable);
+
+ QList<Custom> null;
+ QList<Custom> empty(0, '0');
+ QList<Custom> emptyReserved;
+ QList<Custom> nonEmpty;
+ QList<Custom> nonEmptyReserved;
+
+ emptyReserved.reserve(10);
+ nonEmptyReserved.reserve(15);
+ nonEmpty << '0' << '1' << '2' << '3' << '4';
+ nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
+ QVERIFY(emptyReserved.capacity() >= 10);
+ QVERIFY(nonEmptyReserved.capacity() >= 15);
+
+ QTest::newRow("null") << null << 10;
+ QTest::newRow("null and 0 size") << null << 0;
+ QTest::newRow("empty") << empty << 10;
+ QTest::newRow("empty and 0 size") << empty << 0;
+ QTest::newRow("emptyReserved") << emptyReserved << 10;
+ QTest::newRow("nonEmpty") << nonEmpty << 10;
+ QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
+}
+
+void tst_QList::resizeComplex() const
+{
+ const int items = Custom::counter.loadAcquire();
+ {
+ QFETCH(QList<Custom>, vector);
+ QFETCH(int, size);
+
+ int oldSize = vector.size();
+ vector.resize(size);
+ QCOMPARE(vector.size(), size);
+ QVERIFY(vector.capacity() >= size);
+ if (vector.isEmpty())
+ QVERIFY(!vector.isDetached());
+ for (int i = oldSize; i < size; ++i)
+ QVERIFY(vector[i].i == 'j'); // check default initialization
+
+ const int capacity = vector.capacity();
+
+ vector.resize(0);
+ QCOMPARE(vector.size(), 0);
+ QVERIFY(vector.isEmpty());
+ QVERIFY(vector.capacity() <= capacity);
+ }
+ QCOMPARE(Custom::counter.loadAcquire(), items);
+}
+
+void tst_QList::resizeCtorAndDtor() const
+{
+ const int items = Custom::counter.loadAcquire();
+ {
+ QList<Custom> null;
+ QList<Custom> empty(0, '0');
+ QList<Custom> emptyReserved;
+ QList<Custom> nonEmpty;
+ QList<Custom> nonEmptyReserved;
+
+ emptyReserved.reserve(10);
+ nonEmptyReserved.reserve(15);
+ nonEmpty << '0' << '1' << '2' << '3' << '4';
+ nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
+ QVERIFY(emptyReserved.capacity() >= 10);
+ QVERIFY(nonEmptyReserved.capacity() >= 15);
+
+ // start playing with vectors
+ null.resize(21);
+ nonEmpty.resize(2);
+ emptyReserved.resize(0);
+ nonEmpty.resize(0);
+ nonEmptyReserved.resize(2);
+ }
+ QCOMPARE(Custom::counter.loadAcquire(), items);
+}
+
+void tst_QList::resizeToZero() const
+{
+ QList<int> x;
+ QList<int> y;
+ x << 1 << 2;
+ y = x;
+ y.resize(0);
+ QCOMPARE(y.size(), 0);
+ // grow back
+ y.resize(x.size());
+ QCOMPARE(y.size(), x.size());
+ // default initialized
+ QCOMPARE(y[0], 0);
+ QCOMPARE(y[1], 0);
+}
+
+void tst_QList::resizeToTheSameSize_data()
+{
+ QTest::addColumn<QList<int>>("x");
+ QTest::newRow("size 2") << QList({ 1, 2 });
+ QTest::newRow("size 0") << QList<int>();
+}
+
+void tst_QList::resizeToTheSameSize() const
+{
+ QFETCH(QList<int>, x);
+ QList<int> y;
+ y = x;
+ y.resize(x.size());
+ QCOMPARE(y.size(), x.size());
+}
+
+void tst_QList::resizeForOverwrite() const
+{
+ constexpr int BUILD_COUNT = 42;
+ {
+ // Smoke test
+ QList<int> l(BUILD_COUNT, Qt::Uninitialized);
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ }
+
+ {
+ const int beforeCounter = Movable::counter.loadRelaxed();
+ QList<Movable> l(BUILD_COUNT, Qt::Uninitialized);
+ const int after1Counter = Movable::counter.loadRelaxed();
+ QCOMPARE(after1Counter, beforeCounter + BUILD_COUNT);
+
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ const int after2Counter = Movable::counter.loadRelaxed();
+ QCOMPARE(after2Counter, after1Counter + BUILD_COUNT);
+ }
+
+ struct QtInitializationSupport {
+ bool wasInitialized;
+ QtInitializationSupport() : wasInitialized(true) {}
+ explicit QtInitializationSupport(Qt::Initialization) : wasInitialized(false) {}
+ };
+
+ {
+ QList<QtInitializationSupport> l(BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(elem.wasInitialized);
+ l.resize(l.size() + BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(elem.wasInitialized);
+ }
+
+ {
+ QList<QtInitializationSupport> l(BUILD_COUNT, Qt::Uninitialized);
+ for (const auto &elem : l)
+ QVERIFY(!elem.wasInitialized);
+ l.resizeForOverwrite(l.size() + BUILD_COUNT);
+ for (const auto &elem : l)
+ QVERIFY(!elem.wasInitialized);
+ }
+}
+
+void tst_QList::iterators() const
+{
+ QList<int> v;
+
+ QCOMPARE(v.begin(), v.end());
+ QCOMPARE(v.rbegin(), v.rend());
+
+ qsizetype idx = 0;
+ for (; idx < 10; ++idx)
+ v.push_back(idx);
+
+ // stl-style iterators
+ idx = 0;
+ auto it = v.begin();
+ QCOMPARE(*it, idx);
+ // idx == 0
+
+ std::advance(it, 7);
+ idx += 7;
+ QCOMPARE(*it, idx);
+ // idx == 7
+
+ it++;
+ idx++;
+ QCOMPARE(*it, idx);
+ // idx == 8
+
+ ++it;
+ ++idx;
+ QCOMPARE(*it, idx);
+ // idx == 9
+
+ std::advance(it, -3);
+ idx -= 3;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it--;
+ idx--;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ --it;
+ --idx;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ it = it + 1;
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ it = it + ptrdiff_t(1);
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it = it + qsizetype(1);
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 7
+
+ it = it - qsizetype(1);
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it = it - ptrdiff_t(1);
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ it = it - 1;
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ it -= 1;
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 3
+
+ it -= qsizetype(1);
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 2
+
+ it -= ptrdiff_t(1);
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 1
+
+ it += ptrdiff_t(1);
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 2
+
+ it += qsizetype(1);
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 3
+
+ it += 1;
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ *it = idx + 1;
+ QCOMPARE(*it, idx + 1);
+ *it = idx;
+
+ // stl-style reverse iterators
+ idx = v.size() - 1;
+ auto rit = v.rbegin();
+ QCOMPARE(*rit, idx);
+
+ *rit = idx + 1;
+ QCOMPARE(*rit, idx + 1);
+ *rit = idx;
+
+ std::advance(rit, 5);
+ idx -= 5;
+ QCOMPARE(*rit, idx);
+
+ ++rit;
+ --idx;
+ QCOMPARE(*rit, idx);
+
+ rit++;
+ idx--;
+ QCOMPARE(*rit, idx);
+
+ std::advance(rit, -4);
+ idx += 4;
+ QCOMPARE(*rit, idx);
+
+ --rit;
+ ++idx;
+ QCOMPARE(*rit, idx);
+
+ rit--;
+ idx++;
+ QCOMPARE(*rit, idx);
+}
+
+void tst_QList::constIterators() const
+{
+ const QList<int> constEmptyList;
+ QCOMPARE(constEmptyList.cbegin(), constEmptyList.cend());
+ QCOMPARE(constEmptyList.begin(), constEmptyList.cbegin());
+ QCOMPARE(constEmptyList.end(), constEmptyList.cend());
+ QCOMPARE(constEmptyList.constBegin(), constEmptyList.constEnd());
+ QCOMPARE(constEmptyList.constBegin(), constEmptyList.cbegin());
+ QCOMPARE(constEmptyList.constEnd(), constEmptyList.cend());
+ QVERIFY(!constEmptyList.isDetached());
+
+ const QList<int> v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ // stl-style iterators
+ qsizetype idx = 0;
+ auto it = v.cbegin();
+ QCOMPARE(*it, idx);
+ // idx == 0
+
+ std::advance(it, 7);
+ idx += 7;
+ QCOMPARE(*it, idx);
+ // idx == 7
+
+ it++;
+ idx++;
+ QCOMPARE(*it, idx);
+ // idx == 8
+
+ ++it;
+ ++idx;
+ QCOMPARE(*it, idx);
+ // idx == 9
+
+ std::advance(it, -3);
+ idx -= 3;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it--;
+ idx--;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ --it;
+ --idx;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ it = it + 1;
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ it = it + ptrdiff_t(1);
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it = it + qsizetype(1);
+ idx = idx + 1;
+ QCOMPARE(*it, idx);
+ // idx == 7
+
+ it = it - qsizetype(1);
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 6
+
+ it = it - ptrdiff_t(1);
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 5
+
+ it = it - 1;
+ idx = idx - 1;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ it -= 1;
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 3
+
+ it -= qsizetype(1);
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 2
+
+ it -= ptrdiff_t(1);
+ idx -= 1;
+ QCOMPARE(*it, idx);
+ // idx == 1
+
+ it += ptrdiff_t(1);
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 2
+
+ it += qsizetype(1);
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 3
+
+ it += 1;
+ idx += 1;
+ QCOMPARE(*it, idx);
+ // idx == 4
+
+ // stl-style reverse iterators
+ idx = v.size() - 1;
+ auto rit = v.crbegin();
+ QCOMPARE(*rit, idx);
+
+ std::advance(rit, 5);
+ idx -= 5;
+ QCOMPARE(*rit, idx);
+
+ ++rit;
+ --idx;
+ QCOMPARE(*rit, idx);
+
+ rit++;
+ idx--;
+ QCOMPARE(*rit, idx);
+
+ std::advance(rit, -4);
+ idx += 4;
+ QCOMPARE(*rit, idx);
+
+ --rit;
+ ++idx;
+ QCOMPARE(*rit, idx);
+
+ rit--;
+ idx++;
+ QCOMPARE(*rit, idx);
+}
+
+void tst_QList::reverseIterators() const
+{
+ QList<int> v;
+ v << 1 << 2 << 3 << 4;
+ QList<int> vr = v;
+ std::reverse(vr.begin(), vr.end());
+ const QList<int> &cvr = vr;
+ QVERIFY(std::equal(v.begin(), v.end(), vr.rbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), vr.crbegin()));
+ QVERIFY(std::equal(v.begin(), v.end(), cvr.rbegin()));
+ QVERIFY(std::equal(vr.rbegin(), vr.rend(), v.begin()));
+ QVERIFY(std::equal(vr.crbegin(), vr.crend(), v.begin()));
+ QVERIFY(std::equal(cvr.rbegin(), cvr.rend(), v.begin()));
+}
+
+template<typename T>
+void tst_QList::size() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // also verify that length() is an alias to size()
+
+ // zero size
+ QList<T> myvec;
+ QVERIFY(myvec.size() == 0);
+ QCOMPARE(myvec.size(), myvec.size());
+ QVERIFY(!myvec.isDetached());
+
+ // grow
+ myvec.append(SimpleValue<T>::at(0));
+ QVERIFY(myvec.size() == 1);
+ QCOMPARE(myvec.size(), myvec.size());
+ myvec.append(SimpleValue<T>::at(1));
+ QVERIFY(myvec.size() == 2);
+ QCOMPARE(myvec.size(), myvec.size());
+
+ // shrink
+ myvec.remove(0);
+ QVERIFY(myvec.size() == 1);
+ QCOMPARE(myvec.size(), myvec.size());
+ myvec.remove(0);
+ QVERIFY(myvec.size() == 0);
+ QCOMPARE(myvec.size(), myvec.size());
+}
+
+// ::squeeze() is tested in ::capacity().
+
+void tst_QList::startsWith() const
+{
+ QList<int> myvec;
+
+ // empty vector
+ QVERIFY(!myvec.startsWith(1));
+
+ // add the one, should work
+ myvec.prepend(1);
+ QVERIFY(myvec.startsWith(1));
+
+ // add something else, fails now
+ myvec.prepend(3);
+ QVERIFY(!myvec.startsWith(1));
+
+ // remove it again :)
+ myvec.remove(0);
+ QVERIFY(myvec.startsWith(1));
+}
+
+template<typename T>
+void tst_QList::swap() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> v1, v2;
+ T val1 = SimpleValue<T>::at(0);
+ T val2 = SimpleValue<T>::at(1);
+ T val3 = SimpleValue<T>::at(2);
+ T val4 = SimpleValue<T>::at(3);
+ T val5 = SimpleValue<T>::at(4);
+ T val6 = SimpleValue<T>::at(5);
+ v1 << val1 << val2 << val3;
+ v2 << val4 << val5 << val6;
+
+ v1.swap(v2);
+ QCOMPARE(v1,QList<T>() << val4 << val5 << val6);
+ QCOMPARE(v2,QList<T>() << val1 << val2 << val3);
+}
+
+void tst_QList::toList() const
+{
+ QList<QString> myvec;
+ myvec << "A" << "B" << "C";
+
+ // make sure it converts and doesn't modify the original vector
+ QCOMPARE(myvec.toList(), QList<QString>() << "A" << "B" << "C");
+ QCOMPARE(myvec, QList<QString>() << "A" << "B" << "C");
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+void tst_QList::toStdVector() const
+{
+ QList<QString> myvec;
+ myvec << "A" << "B" << "C";
+
+ std::vector<QString> svec = myvec.toStdVector();
+ QCOMPARE(svec.at(0), QLatin1String("A"));
+ QCOMPARE(svec.at(1), QLatin1String("B"));
+ QCOMPARE(svec.at(2), QLatin1String("C"));
+
+ QCOMPARE(myvec, QList<QString>() << "A" << "B" << "C");
+}
+#endif
+
+void tst_QList::value() const
+{
+ QList<QString> myvec;
+
+ QCOMPARE(myvec.value(1), QString());
+ QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default"));
+ QVERIFY(!myvec.isDetached());
+
+ myvec << "A" << "B" << "C";
+
+ // valid calls
+ QCOMPARE(myvec.value(0), QLatin1String("A"));
+ QCOMPARE(myvec.value(1), QLatin1String("B"));
+ QCOMPARE(myvec.value(2), QLatin1String("C"));
+
+ // default calls
+ QCOMPARE(myvec.value(-1), QString());
+ QCOMPARE(myvec.value(3), QString());
+
+ // test calls with a provided default, valid calls
+ QCOMPARE(myvec.value(0, QLatin1String("default")), QLatin1String("A"));
+ QCOMPARE(myvec.value(1, QLatin1String("default")), QLatin1String("B"));
+ QCOMPARE(myvec.value(2, QLatin1String("default")), QLatin1String("C"));
+
+ // test calls with a provided default that will return the default
+ QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default"));
+ QCOMPARE(myvec.value(3, QLatin1String("default")), QLatin1String("default"));
+}
+
+void tst_QList::testOperators() const
+{
+ QList<QString> myvec;
+ myvec << "A" << "B" << "C";
+ QList<QString> myvectwo;
+ myvectwo << "D" << "E" << "F";
+ QList<QString> combined;
+ combined << "A" << "B" << "C" << "D" << "E" << "F";
+
+ // !=
+ QVERIFY(myvec != myvectwo);
+
+ // +
+ QCOMPARE(myvec + myvectwo, combined);
+ QCOMPARE(myvec, QList<QString>() << "A" << "B" << "C");
+ QCOMPARE(myvectwo, QList<QString>() << "D" << "E" << "F");
+
+ // +=
+ myvec += myvectwo;
+ QCOMPARE(myvec, combined);
+
+ // ==
+ QVERIFY(myvec == combined);
+
+ // <, >, <=, >=
+ QVERIFY(!(myvec < combined));
+ QVERIFY(!(myvec > combined));
+ QVERIFY( myvec <= combined);
+ QVERIFY( myvec >= combined);
+ combined.push_back("G");
+ QVERIFY( myvec < combined);
+ QVERIFY(!(myvec > combined));
+ QVERIFY( myvec <= combined);
+ QVERIFY(!(myvec >= combined));
+ QVERIFY(combined > myvec);
+ QVERIFY(combined >= myvec);
+
+ // []
+ QCOMPARE(myvec[0], QLatin1String("A"));
+ QCOMPARE(myvec[1], QLatin1String("B"));
+ QCOMPARE(myvec[2], QLatin1String("C"));
+ QCOMPARE(myvec[3], QLatin1String("D"));
+ QCOMPARE(myvec[4], QLatin1String("E"));
+ QCOMPARE(myvec[5], QLatin1String("F"));
+}
+
+
+int fooCtor;
+int fooDtor;
+
+struct Foo
+{
+ int *p;
+
+ Foo() { p = new int; ++fooCtor; }
+ Foo(const Foo &other) { Q_UNUSED(other); p = new int; ++fooCtor; }
+
+ void operator=(const Foo & /* other */) { }
+
+ ~Foo() { delete p; ++fooDtor; }
+};
+
+void tst_QList::reserve()
+{
+ fooCtor = 0;
+ fooDtor = 0;
+ {
+ QList<Foo> a;
+ a.resize(2);
+ QCOMPARE(fooCtor, 2);
+ QList<Foo> b(a);
+ b.reserve(1);
+ QCOMPARE(b.size(), a.size());
+ QCOMPARE(fooDtor, 0);
+ }
+ QCOMPARE(fooCtor, fooDtor);
+}
+
+// This is a regression test for QTBUG-51758
+void tst_QList::reserveZero()
+{
+ QList<int> vec;
+ vec.detach();
+ vec.reserve(0); // should not crash
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.squeeze();
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.reserve(-1);
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.append(42);
+ QCOMPARE(vec.size(), 1);
+ QVERIFY(vec.capacity() >= 1);
+
+ QList<int> vec2;
+ vec2.reserve(0); // should not crash either
+ vec2.reserve(-1);
+ vec2.squeeze();
+ QCOMPARE(vec2.size(), 0);
+ QCOMPARE(vec2.capacity(), 0);
+ QVERIFY(!vec2.isDetached());
+}
+
+template<typename T>
+void tst_QList::initializeList()
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ T val1(SimpleValue<T>::at(1));
+ T val2(SimpleValue<T>::at(2));
+ T val3(SimpleValue<T>::at(3));
+ T val4(SimpleValue<T>::at(4));
+
+ QList<T> v1 {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+
+ QList<QList<T>> v2{ v1, {val4}, QList<T>(), {val1, val2, val3} };
+ QList<QList<T>> v3;
+ v3 << v1 << (QList<T>() << val4) << QList<T>() << v1;
+ QCOMPARE(v3, v2);
+
+ QList<T> v4({});
+ QCOMPARE(v4.size(), 0);
+}
+
+void tst_QList::const_shared_null()
+{
+ QList<int> v2;
+ QVERIFY(!v2.isDetached());
+}
+
+template<typename T>
+void tst_QList::detach() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ // detach an empty vector
+ QList<T> v;
+ v.detach();
+ QVERIFY(!v.isDetached());
+ QCOMPARE(v.size(), 0);
+ QCOMPARE(v.capacity(), 0);
+ }
+ {
+ // detach an empty referenced vector
+ QList<T> v;
+ QList<T> ref(v);
+ QVERIFY(!v.isDetached());
+ v.detach();
+ QVERIFY(!v.isDetached());
+ QCOMPARE(v.size(), 0);
+ QCOMPARE(v.capacity(), 0);
+ }
+ {
+ // detach a not empty referenced vector
+ QList<T> v(31);
+ QList<T> ref(v);
+ QVERIFY(!v.isDetached());
+ v.detach();
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 31);
+ QCOMPARE(v.capacity(), 31);
+ }
+ {
+ // detach a not empty vector
+ QList<T> v(31);
+ QVERIFY(v.isDetached());
+ v.detach(); // detaching a detached vector
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 31);
+ QCOMPARE(v.capacity(), 31);
+ }
+ {
+ // detach a not empty vector with preallocated space
+ QList<T> v(3);
+ v.reserve(8);
+ QList<T> ref(v);
+ QVERIFY(!v.isDetached());
+ v.detach();
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 3);
+ QCOMPARE(v.capacity(), 8);
+ }
+ {
+ // detach a not empty vector with preallocated space
+ QList<T> v(3);
+ v.reserve(8);
+ QVERIFY(v.isDetached());
+ v.detach(); // detaching a detached vector
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 3);
+ QCOMPARE(v.capacity(), 8);
+ }
+ {
+ // detach a not empty, initialized vector
+ QList<T> v(7, SimpleValue<T>::at(1));
+ QList<T> ref(v);
+ QVERIFY(!v.isDetached());
+ v.detach();
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 7);
+ for (int i = 0; i < v.size(); ++i)
+ QCOMPARE(v[i], SimpleValue<T>::at(1));
+ }
+ {
+ // detach a not empty, initialized vector
+ QList<T> v(7, SimpleValue<T>::at(2));
+ QVERIFY(v.isDetached());
+ v.detach(); // detaching a detached vector
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 7);
+ for (int i = 0; i < v.size(); ++i)
+ QCOMPARE(v[i], SimpleValue<T>::at(2));
+ }
+ {
+ // detach a not empty, initialized vector with preallocated space
+ QList<T> v(7, SimpleValue<T>::at(3));
+ v.reserve(31);
+ QList<T> ref(v);
+ QVERIFY(!v.isDetached());
+ v.detach();
+ QVERIFY(v.isDetached());
+ QCOMPARE(v.size(), 7);
+ QCOMPARE(v.capacity(), 31);
+ for (int i = 0; i < v.size(); ++i)
+ QCOMPARE(v[i], SimpleValue<T>::at(3));
+ }
+}
+
+static QAtomicPointer<QList<int> > detachThreadSafetyDataInt;
+static QAtomicPointer<QList<Movable> > detachThreadSafetyDataMovable;
+static QAtomicPointer<QList<Custom> > detachThreadSafetyDataCustom;
+
+template<typename T> QAtomicPointer<QList<T> > *detachThreadSafetyData();
+template<> QAtomicPointer<QList<int> > *detachThreadSafetyData() { return &detachThreadSafetyDataInt; }
+template<> QAtomicPointer<QList<Movable> > *detachThreadSafetyData() { return &detachThreadSafetyDataMovable; }
+template<> QAtomicPointer<QList<Custom> > *detachThreadSafetyData() { return &detachThreadSafetyDataCustom; }
+
+static QSemaphore detachThreadSafetyLock;
+
+template<typename T>
+void tst_QList::detachThreadSafety() const
+{
+ delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(new QList<T>(SimpleValue<T>::vector(400)));
+
+ static const uint threadsCount = 5;
+
+ struct : QThread {
+ void run() override
+ {
+ QList<T> copy(*detachThreadSafetyData<T>()->loadRelaxed());
+ QVERIFY(!copy.isDetached());
+ detachThreadSafetyLock.release();
+ detachThreadSafetyLock.acquire(100);
+ copy.detach();
+ }
+ } threads[threadsCount];
+
+ for (uint i = 0; i < threadsCount; ++i)
+ threads[i].start();
+ QThread::yieldCurrentThread();
+ detachThreadSafetyLock.acquire(threadsCount);
+
+ // destroy static original data
+ delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(0);
+
+ QVERIFY(threadsCount < 100);
+ detachThreadSafetyLock.release(threadsCount * 100);
+ QThread::yieldCurrentThread();
+
+ for (uint i = 0; i < threadsCount; ++i)
+ threads[i].wait();
+}
+
+void tst_QList::detachThreadSafetyInt() const
+{
+ for (uint i = 0; i < 128; ++i)
+ detachThreadSafety<int>();
+}
+
+void tst_QList::detachThreadSafetyMovable() const
+{
+ const int instancesCount = Movable::counter.loadAcquire();
+ for (uint i = 0; i < 128; ++i) {
+ detachThreadSafety<Movable>();
+ QCOMPARE(Movable::counter.loadAcquire(), instancesCount);
+ }
+}
+
+void tst_QList::detachThreadSafetyCustom() const
+{
+ const int instancesCount = Custom::counter.loadAcquire();
+ for (uint i = 0; i < 128; ++i) {
+ detachThreadSafety<Custom>();
+ QCOMPARE(Custom::counter.loadAcquire(), instancesCount);
+ }
+}
+
+void tst_QList::insertMove() const
+{
+ const int instancesCount = Movable::counter.loadAcquire();
+ {
+ QList<Movable> vec;
+ vec.reserve(7);
+ Movable m0;
+ Movable m1;
+ Movable m2;
+ Movable m3;
+ Movable m4;
+ Movable m5;
+ Movable m6;
+
+ vec.append(std::move(m3));
+ QVERIFY(m3.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m3));
+ vec.push_back(std::move(m4));
+ QVERIFY(m4.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m3));
+ QVERIFY(vec.at(1).wasConstructedAt(&m4));
+ vec.prepend(std::move(m1));
+ QVERIFY(m1.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m1));
+ QVERIFY(vec.at(1).wasConstructedAt(&m3));
+ QVERIFY(vec.at(2).wasConstructedAt(&m4));
+ vec.insert(1, std::move(m2));
+ QVERIFY(m2.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m1));
+ QVERIFY(vec.at(1).wasConstructedAt(&m2));
+ QVERIFY(vec.at(2).wasConstructedAt(&m3));
+ QVERIFY(vec.at(3).wasConstructedAt(&m4));
+ vec += std::move(m5);
+ QVERIFY(m5.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m1));
+ QVERIFY(vec.at(1).wasConstructedAt(&m2));
+ QVERIFY(vec.at(2).wasConstructedAt(&m3));
+ QVERIFY(vec.at(3).wasConstructedAt(&m4));
+ QVERIFY(vec.at(4).wasConstructedAt(&m5));
+ vec << std::move(m6);
+ QVERIFY(m6.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m1));
+ QVERIFY(vec.at(1).wasConstructedAt(&m2));
+ QVERIFY(vec.at(2).wasConstructedAt(&m3));
+ QVERIFY(vec.at(3).wasConstructedAt(&m4));
+ QVERIFY(vec.at(4).wasConstructedAt(&m5));
+ QVERIFY(vec.at(5).wasConstructedAt(&m6));
+ vec.push_front(std::move(m0));
+ QVERIFY(m0.wasConstructedAt(nullptr));
+ QVERIFY(vec.at(0).wasConstructedAt(&m0));
+ QVERIFY(vec.at(1).wasConstructedAt(&m1));
+ QVERIFY(vec.at(2).wasConstructedAt(&m2));
+ QVERIFY(vec.at(3).wasConstructedAt(&m3));
+ QVERIFY(vec.at(4).wasConstructedAt(&m4));
+ QVERIFY(vec.at(5).wasConstructedAt(&m5));
+ QVERIFY(vec.at(6).wasConstructedAt(&m6));
+
+ QCOMPARE(Movable::counter.loadAcquire(), instancesCount + 14);
+ }
+ QCOMPARE(Movable::counter.loadAcquire(), instancesCount);
+}
+
+void tst_QList::swapItemsAt() const
+{
+ QList<int> v;
+ v << 0 << 1 << 2 << 3;
+
+ v.swapItemsAt(0, 2);
+ QCOMPARE(v.at(0), 2);
+ QCOMPARE(v.at(2), 0);
+
+ auto copy = v;
+ copy.swapItemsAt(0, 2);
+ QCOMPARE(v.at(0), 2);
+ QCOMPARE(v.at(2), 0);
+ QCOMPARE(copy.at(0), 0);
+ QCOMPARE(copy.at(2), 2);
+}
+
+void tst_QList::emplaceReturnsIterator()
+{
+ QList<Movable> vec;
+
+ vec.emplace(0, 'k')->i = 'p';
+
+ QCOMPARE(vec[0].i, 'p');
+}
+
+void tst_QList::emplaceFront() const
+{
+ QAtomicScopedValueRollback rollback(Movable::counter, 0);
+
+ QList<Movable> vec;
+ vec.emplaceFront('b');
+ QCOMPARE(Movable::counter, 1);
+
+ vec.emplaceFront('a');
+ QCOMPARE(Movable::counter, 2);
+
+ QCOMPARE(vec, QList<Movable>({ 'a', 'b' }));
+}
+
+void tst_QList::emplaceFrontReturnsRef() const
+{
+ QList<Movable> vec;
+
+ QCOMPARE(vec.emplaceFront('c').i, 'c');
+
+ vec.emplaceFront('b').i = 'a';
+
+ QCOMPARE(vec.front().i, 'a');
+}
+
+void tst_QList::emplaceBack()
+{
+ QAtomicScopedValueRollback rollback(Movable::counter, 0);
+
+ QList<Movable> vec;
+
+ vec.emplaceBack('k');
+
+ QCOMPARE(Movable::counter, 1);
+}
+
+void tst_QList::emplaceBackReturnsRef()
+{
+ QList<Movable> vec;
+
+ vec.emplaceBack('k').i = 'p';
+
+ QCOMPARE(vec.at(0).i, 'p');
+}
+
+void tst_QList::emplaceWithElementFromTheSameContainer()
+{
+ QFETCH(int, elementPos);
+ QFETCH(int, insertPos);
+ QFETCH(bool, doCopy);
+
+ QList<QString> vec {"a", "b", "c", "d", "e"};
+ const QString e = vec[elementPos];
+
+ if (doCopy)
+ vec.emplace(insertPos, vec[elementPos]);
+ else
+ vec.emplace(insertPos, std::move(vec[elementPos]));
+
+ QCOMPARE(vec[insertPos], e);
+}
+
+void tst_QList::emplaceWithElementFromTheSameContainer_data()
+{
+ QTest::addColumn<int>("elementPos");
+ QTest::addColumn<int>("insertPos");
+ QTest::addColumn<bool>("doCopy");
+
+ for (int i = 0; i < 2; ++i) {
+ const bool doCopy = i == 0;
+ const char *opName = doCopy ? "copy" : "move";
+
+ QTest::addRow("%s: begin -> end" , opName) << 0 << 5 << doCopy;
+ QTest::addRow("%s: begin -> middle", opName) << 0 << 2 << doCopy;
+ QTest::addRow("%s: middle -> begin" , opName) << 2 << 0 << doCopy;
+ QTest::addRow("%s: middle -> end" , opName) << 2 << 5 << doCopy;
+ QTest::addRow("%s: end -> middle", opName) << 4 << 2 << doCopy;
+ QTest::addRow("%s: end -> begin" , opName) << 4 << 0 << doCopy;
+ }
+}
+
+template<typename T>
+void tst_QList::emplaceImpl() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> vec {'a', 'b', 'c', 'd'};
+
+ vec.emplace(2, 'k');
+
+ QCOMPARE(vec.size(), 5); // emplace adds new element
+ QCOMPARE(vec[2], T('k'));
+
+ vec.emplace(vec.end(), T('f'));
+
+ QCOMPARE(vec.size(), 6);
+ QCOMPARE(vec.back(), T('f'));
+
+ // emplace() into empty container
+ {
+ QList<T> vec;
+ vec.emplace(vec.begin(), 'a');
+ QCOMPARE(vec.size(), 1);
+ QCOMPARE(vec.front(), T('a'));
+ }
+ {
+ QList<T> vec;
+ vec.emplace(0, 'a');
+ QCOMPARE(vec.size(), 1);
+ QCOMPARE(vec.front(), T('a'));
+ }
+}
+
+template <typename T>
+void tst_QList::replace() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> vec { 'a', 'b', 'c', 'd' };
+ T e = 'e';
+ vec.replace(0, e);
+ QCOMPARE(vec[0], T('e'));
+
+ T f = 'f';
+ vec.replace(2, std::move(f));
+ QCOMPARE(vec[2], T('f'));
+}
+
+template <class T>
+static void vecEq(const QList<T> &qVec, const std::vector<T> &stdVec)
+{
+ QCOMPARE(std::size_t(qVec.size()), stdVec.size());
+ QVERIFY(std::equal(qVec.begin(), qVec.end(), stdVec.begin(), stdVec.end()));
+}
+
+template <class T>
+static void squeezeVec(QList<T> &qVec, std::vector<T> &stdVec)
+{
+ qVec.squeeze();
+ stdVec.shrink_to_fit();
+}
+
+template<typename T>
+void tst_QList::emplaceConsistentWithStdVectorImpl() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // fast-patch to make QString work with the old logic
+ const auto convert = [] (char i) {
+ if constexpr (std::is_same_v<QString, T>) {
+ return QChar(i);
+ } else {
+ return i;
+ }
+ };
+
+ QList<T> qVec {convert('a'), convert('b'), convert('c'), convert('d'), convert('e')};
+ std::vector<T> stdVec {convert('a'), convert('b'), convert('c'), convert('d'), convert('e')};
+ vecEq(qVec, stdVec);
+
+ qVec.emplaceBack(convert('f'));
+ stdVec.emplace_back(convert('f'));
+ vecEq(qVec, stdVec);
+
+ qVec.emplace(3, convert('g'));
+ stdVec.emplace(stdVec.begin() + 3, convert('g'));
+ vecEq(qVec, stdVec);
+
+ T t;
+ // while QList is safe with regards to emplacing elements moved from itself, it's UB
+ // for std::vector, so do the moving in two steps there.
+ qVec.emplaceBack(std::move(qVec[0]));
+ stdVec.emplace_back(std::move(t = std::move(stdVec[0])));
+ vecEq(qVec, stdVec);
+
+ squeezeVec(qVec, stdVec);
+
+ qVec.emplaceBack(std::move(qVec[1]));
+ stdVec.emplace_back(std::move(t = std::move(stdVec[1])));
+ vecEq(qVec, stdVec);
+
+ squeezeVec(qVec, stdVec);
+
+ qVec.emplace(3, std::move(qVec[5]));
+ stdVec.emplace(stdVec.begin() + 3, std::move(t = std::move(stdVec[5])));
+
+ vecEq(qVec, stdVec);
+
+ qVec.emplaceBack(qVec[3]);
+ stdVec.emplace_back((t = stdVec[3]));
+ vecEq(qVec, stdVec);
+
+ squeezeVec(qVec, stdVec);
+
+ qVec.emplaceBack(qVec[4]);
+ stdVec.emplace_back((t = stdVec[4]));
+ vecEq(qVec, stdVec);
+
+ squeezeVec(qVec, stdVec);
+
+ qVec.emplace(5, qVec[7]);
+ stdVec.emplace(stdVec.begin() + 5, (t = stdVec[7]));
+ vecEq(qVec, stdVec);
+}
+
+void tst_QList::fromReadOnlyData() const
+{
+ {
+ QVector<char> d = QVector<char>::fromReadOnlyData("ABCDEFGHIJ");
+ QCOMPARE(d.capacity(), 0);
+ d.squeeze();
+ QCOMPARE(d.capacity(), 0);
+ QCOMPARE(d.size(), 10u + 1u);
+ for (int i = 0; i < 10; ++i)
+ QCOMPARE(d.data()[i], char('A' + i));
+ }
+
+ {
+ // wchar_t is not necessarily 2-bytes
+ QVector<wchar_t> d = QVector<wchar_t>::fromReadOnlyData(L"ABCDEFGHIJ");
+ QCOMPARE(d.size(), 10u + 1u);
+ for (int i = 0; i < 10; ++i)
+ QCOMPARE(d.data()[i], wchar_t('A' + i));
+ QVERIFY(d.isDetached());
+ }
+
+ {
+ const char data[] = "ABCDEFGHIJ";
+ const QVector<char> v = QVector<char>::fromReadOnlyData(data);
+
+ QVERIFY(v.constData() == data);
+ QVERIFY(!v.isEmpty());
+ QCOMPARE(v.size(), qsizetype(11));
+ // v.capacity() is unspecified, for now
+
+ QCOMPARE((void*)(v.constBegin() + v.size()).operator->(), (void*)v.constEnd().operator->());
+
+ for (int i = 0; i < 10; ++i)
+ QCOMPARE(v[i], char('A' + i));
+ QCOMPARE(v[10], char('\0'));
+ }
+
+ {
+ struct LiteralType {
+ int value;
+ constexpr LiteralType(int v = 0) : value(v) {}
+ };
+ const LiteralType literal[] = {LiteralType(0), LiteralType(1), LiteralType(2)};
+
+ const QVector<LiteralType> d = QVector<LiteralType>::fromReadOnlyData(literal);
+ QCOMPARE(d.size(), 3);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(d.data()[i].value, i);
+ }
+}
+
+struct alignas(8) CustomAligned
+{
+ qint64 v = 0;
+ CustomAligned() = default;
+ CustomAligned(qint64 i) : v(i) { }
+ friend bool operator==(const CustomAligned &x, const CustomAligned &y) { return x.v == y.v; }
+};
+
+void tst_QList::reallocateCustomAlignedType_qtbug90359() const
+{
+ // Note: a very special test that could only fail for specific alignments
+ constexpr bool canFail = (alignof(QArrayData) == 4) && (sizeof(QArrayData) == 12);
+ if constexpr (!canFail)
+ qWarning() << "This test will always succeed on this system.";
+ if constexpr (alignof(CustomAligned) > alignof(std::max_align_t))
+ QSKIP("The codepaths tested here wouldn't be executed.");
+
+ const QList<CustomAligned> expected({ 0, 1, 2, 3, 4, 5, 6 });
+ QList<CustomAligned> actual;
+ for (int i = 0; i < 7; ++i) {
+ actual.append(i);
+ QCOMPARE(actual.at(i), i);
+ }
+ QCOMPARE(actual, expected);
+}
+
+template<typename T, typename Reinsert>
+void tst_QList::reinsert(Reinsert op) const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ QList<T> list(1);
+ // this constant is big enough for the QList to stop reallocating, after
+ // all, size is always less than 3
+ const int maxIters = 128;
+ for (int i = 0; i < maxIters; ++i) {
+ op(list);
+ }
+
+ // if QList continues to grow, it's an error
+ qsizetype capacity = list.capacity();
+ for (int i = 0, enoughIters = int(capacity) * 2; i < enoughIters; ++i) {
+ op(list);
+ QCOMPARE(capacity, list.capacity());
+ }
+}
+
+template<typename T>
+void tst_QList::stability_reserve() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // NOTE: this test verifies that QList::constData() stays unchanged when
+ // inserting as much as requested by the reserve. This is specifically
+ // designed this way as in cases when QTypeInfo<T>::isRelocatable returns
+ // true, reallocation might use fast ::realloc() path which may in theory
+ // (and, actually, in practice) just expand the current memory area and thus
+ // keep QList::constData() unchanged, which means checks like
+ // QVERIFY(oldConstData != vec.constData()) are flaky. When
+ // QTypeInfo<T>::isRelocatable returns false, constData() will always change
+ // if a reallocation happens and this will fail the test. This should be
+ // sufficient on its own to test the stability requirements.
+
+ {
+ QList<T> vec;
+ vec.reserve(64);
+ const T *ptr = vec.constData();
+ vec.append(QList<T>(64));
+ QCOMPARE(ptr, vec.constData());
+ }
+
+ {
+ QList<T> vec;
+ vec.prepend(SimpleValue<T>::at(0));
+ vec.removeFirst();
+ vec.reserve(64);
+ const T *ptr = vec.constData();
+ vec.append(QList<T>(64));
+ QCOMPARE(ptr, vec.constData());
+ }
+
+ {
+ QList<T> vec;
+ const T *ptr = vec.constData();
+ vec.reserve(vec.capacity());
+ QCOMPARE(ptr, vec.constData());
+ vec.append(QList<T>(vec.capacity()));
+ QCOMPARE(ptr, vec.constData());
+ }
+
+ {
+ QList<T> vec;
+ vec.prepend(SimpleValue<T>::at(0));
+ vec.removeFirst();
+ vec.reserve(vec.capacity());
+ const T *ptr = vec.constData();
+ vec.append(QList<T>(vec.capacity()));
+ QCOMPARE(ptr, vec.constData());
+ }
+
+ {
+ QList<T> vec;
+ vec.append(SimpleValue<T>::at(0));
+ vec.reserve(64);
+ const T *ptr = vec.constData();
+ vec.append(QList<T>(64 - vec.size())); // 1 element is already in the container
+ QCOMPARE(ptr, vec.constData());
+ QCOMPARE(vec.size(), 64);
+ QCOMPARE(vec.capacity(), 64);
+ const qsizetype oldCapacity = vec.capacity();
+ vec.append(SimpleValue<T>::at(1)); // will reallocate as this exceeds 64
+ QVERIFY(oldCapacity < vec.capacity());
+ }
+
+ {
+ QList<T> vec;
+ vec.prepend(SimpleValue<T>::at(0));
+ vec.reserve(64);
+ const T *ptr = vec.constData();
+ vec.append(QList<T>(64 - vec.size())); // 1 element is already in the container
+ QCOMPARE(ptr, vec.constData());
+ QCOMPARE(vec.size(), 64);
+ QCOMPARE(vec.capacity(), 64);
+ const qsizetype oldCapacity = vec.capacity();
+ vec.append(SimpleValue<T>::at(1)); // will reallocate as this exceeds 64
+ QVERIFY(oldCapacity < vec.capacity());
+ }
+}
+
+template<typename T>
+void tst_QList::stability_erase() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // invalidated: [pos, end())
+ for (int pos = 1; pos < 10; ++pos) {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ const auto ptr = v.constData();
+
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.begin() + pos);
+
+ v.remove(pos, 1);
+ QVERIFY(ptr == v.constData());
+ for (int i = 0; i < copy.size(); ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+
+ // 0 is a special case, because all values get invalidated
+ {
+ QList<T> v(10);
+ const auto ptr = v.constData();
+ v.remove(0, 2);
+ QVERIFY(ptr != v.constData()); // can do fast removal from begin()
+ }
+
+ // when erasing everything, leave the data pointer in place (not strictly
+ // required, but this makes more sense in general)
+ {
+ QList<T> v(10);
+ const auto ptr = v.constData();
+ v.remove(0, v.size());
+ QVERIFY(ptr == v.constData());
+ }
+}
+
+template<typename T>
+void tst_QList::stability_append() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ QList<T> src(1, SimpleValue<T>::at(0));
+ v.append(src.begin(), src.end());
+ QCOMPARE_LE(v.size(), v.capacity());
+
+ for (int i = 0; i < v.capacity() - v.size(); ++i) {
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+ v.append(SimpleValue<T>::at(i));
+ for (int i = 0; i < copy.size(); ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+ }
+
+ {
+ QList<T> v;
+ v.reserve(10);
+ const qsizetype capacity = v.capacity();
+ const T *ptr = v.constData();
+ v.prepend(SimpleValue<T>::at(0));
+ // here we abuse the internal details of QList. since there's enough
+ // free space, QList should've only rearranged the data in memory,
+ // without reallocating.
+ QCOMPARE(capacity, v.capacity()); // otherwise cannot rely on ptr
+ const qsizetype freeSpaceAtBegin = v.constData() - ptr;
+ const qsizetype freeSpaceAtEnd = v.capacity() - v.size() - freeSpaceAtBegin;
+ QVERIFY(freeSpaceAtEnd > 0); // otherwise this test is useless
+ QVERIFY(v.size() + freeSpaceAtBegin + freeSpaceAtEnd == v.capacity());
+
+ for (int i = 0; i < freeSpaceAtEnd; ++i) {
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+ QList<T> src(1, SimpleValue<T>::at(i));
+ v.append(src.begin(), src.end());
+ for (int i = 0; i < copy.size(); ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+ }
+}
+
+template<typename T, typename Insert>
+void tst_QList::stability_insert(Insert op) const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ // invalidated: [pos, end())
+ for (int pos = 1; pos <= 10; ++pos) {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ v.append(SimpleValue<T>::at(0)); // causes growth
+ v.removeLast();
+ QCOMPARE(v.size(), 10);
+ QVERIFY(v.size() < v.capacity());
+
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.begin() + pos);
+ op(v, pos, SimpleValue<T>::at(0));
+ for (int i = 0; i < pos; ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+
+ for (int pos = 1; pos <= 10; ++pos) {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ v.prepend(SimpleValue<T>::at(0)); // causes growth and free space at begin > 0
+ v.removeFirst();
+ QCOMPARE(v.size(), 10);
+ QVERIFY(v.size() < v.capacity());
+
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.begin() + pos);
+ op(v, pos, SimpleValue<T>::at(0));
+ for (int i = 0; i < pos; ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+}
+
+template<typename T>
+void tst_QList::stability_resize() const
+{
+ TST_QLIST_CHECK_LEAKS(T)
+
+ {
+ QList<T> v(10);
+ v.reserve(15);
+ QVERIFY(v.size() < v.capacity());
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+
+ v.resize(15);
+ for (int i = 0; i < copy.size(); ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+
+ {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+
+ v.resize(10);
+ for (int i = 0; i < 10; ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+
+ {
+ QList<T> v(10);
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+
+ v.resize(5);
+ for (int i = 0; i < 5; ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+
+ // special case due to prepend:
+ {
+ QList<T> v;
+ v.reserve(20);
+ const qsizetype capacity = v.capacity();
+ const T *ptr = v.constData();
+ v.prepend(SimpleValue<T>::at(0)); // now there's free space at begin
+ v.resize(10);
+ QVERIFY(v.size() < v.capacity());
+ // here we abuse the internal details of QList. since there's enough
+ // free space, QList should've only rearranged the data in memory,
+ // without reallocating.
+ QCOMPARE(capacity, v.capacity()); // otherwise cannot rely on ptr
+ const qsizetype freeSpaceAtBegin = v.constData() - ptr;
+ const qsizetype freeSpaceAtEnd = v.capacity() - v.size() - freeSpaceAtBegin;
+ QVERIFY(freeSpaceAtEnd > 0); // otherwise this test is useless
+ QVERIFY(v.size() + freeSpaceAtBegin + freeSpaceAtEnd == v.capacity());
+ int k = 0;
+ std::generate(v.begin(), v.end(), [&k]() { return SimpleValue<T>::at(k++); });
+ auto [copy, reference] = qlistCopyAndReferenceFromRange(v.begin(), v.end());
+
+ v.resize(v.size() + freeSpaceAtEnd);
+ for (int i = 0; i < copy.size(); ++i)
+ QCOMPARE(*reference[i], copy[i]);
+ }
+}
+
+QTEST_MAIN(tst_QList)
+#include "tst_qlist.moc"
diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/CMakeLists.txt b/tests/auto/corelib/tools/qmacautoreleasepool/CMakeLists.txt
new file mode 100644
index 0000000000..b968945ac6
--- /dev/null
+++ b/tests/auto/corelib/tools/qmacautoreleasepool/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmacautoreleasepool Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmacautoreleasepool LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qmacautoreleasepool
+ SOURCES
+ tst_qmacautoreleasepool.mm
+ LIBRARIES
+ Qt::CorePrivate
+ ${FWFoundation}
+)
diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro b/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro
deleted file mode 100644
index 8599596344..0000000000
--- a/tests/auto/corelib/tools/qmacautoreleasepool/qmacautoreleasepool.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qmacautoreleasepool
-QT = core testlib
-SOURCES = tst_qmacautoreleasepool.mm
-LIBS += -framework Foundation
diff --git a/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm
index 8f1069f419..e7923b47f3 100644
--- a/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm
+++ b/tests/auto/corelib/tools/qmacautoreleasepool/tst_qmacautoreleasepool.mm
@@ -1,32 +1,9 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QtTest/QtTest>
+#include <QTest>
+
+#include <QtCore/private/qcore_mac_p.h>
#include <Foundation/Foundation.h>
@@ -37,7 +14,6 @@ private slots:
void noPool();
void rootLevelPool();
void stackAllocatedPool();
- void heapAllocatedPool();
};
static id lastDeallocedObject = nil;
@@ -86,26 +62,6 @@ void tst_QMacAutoreleasePool::stackAllocatedPool()
[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/qmakearray/CMakeLists.txt b/tests/auto/corelib/tools/qmakearray/CMakeLists.txt
new file mode 100644
index 0000000000..cec589628f
--- /dev/null
+++ b/tests/auto/corelib/tools/qmakearray/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmakearray Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmakearray LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qmakearray
+ SOURCES
+ tst_qmakearray.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qmakearray/qmakearray.pro b/tests/auto/corelib/tools/qmakearray/qmakearray.pro
deleted file mode 100644
index abb3d9fdbc..0000000000
--- a/tests/auto/corelib/tools/qmakearray/qmakearray.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qmakearray
-QT = core testlib core-private
-SOURCES = $$PWD/tst_qmakearray.cpp
diff --git a/tests/auto/corelib/tools/qmakearray/tst_qmakearray.cpp b/tests/auto/corelib/tools/qmakearray/tst_qmakearray.cpp
index e0d3f52719..1d796452b0 100644
--- a/tests/auto/corelib/tools/qmakearray/tst_qmakearray.cpp
+++ b/tests/auto/corelib/tools/qmakearray/tst_qmakearray.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QtTest/QtTest>
+#include <QTest>
#include <private/qmakearray_p.h>
diff --git a/tests/auto/corelib/tools/qmap/CMakeLists.txt b/tests/auto/corelib/tools/qmap/CMakeLists.txt
new file mode 100644
index 0000000000..bddf9267f8
--- /dev/null
+++ b/tests/auto/corelib/tools/qmap/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmap Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmap LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qmap
+ SOURCES
+ tst_qmap.cpp
+)
+
+qt_internal_undefine_global_definition(tst_qmap QT_NO_JAVA_STYLE_ITERATORS)
diff --git a/tests/auto/corelib/tools/qmap/qmap.pro b/tests/auto/corelib/tools/qmap/qmap.pro
deleted file mode 100644
index 2cc772720d..0000000000
--- a/tests/auto/corelib/tools/qmap/qmap.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qmap
-QT = core testlib
-SOURCES = $$PWD/tst_qmap.cpp
-
-DEFINES -= QT_NO_JAVA_STYLE_ITERATORS
diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
index 85733639b8..6950dcf705 100644
--- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp
+++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
@@ -1,42 +1,22 @@
-/****************************************************************************
-**
-** 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 <qmap.h>
-#include <QtTest/QtTest>
+#include <QTest>
+
#include <QDebug>
+#include <QScopeGuard>
+
+using namespace Qt::StringLiterals;
+QT_WARNING_DISABLE_DEPRECATED
class tst_QMap : public QObject
{
Q_OBJECT
protected:
- template <class KEY, class VALUE>
- void sanityCheckTree(const QMap<KEY, VALUE> &m, int calledFromLine);
+ template <class Map>
+ void sanityCheckTree(const Map &m, int calledFromLine);
public slots:
void init();
private slots:
@@ -46,6 +26,7 @@ private slots:
void beginEnd();
void firstLast();
void key();
+ void value();
void swap();
@@ -60,8 +41,13 @@ private slots:
void take();
void iterators();
+ void multimapIterators();
+ void iteratorsInEmptyMap();
void keyIterator();
+ void multimapKeyIterator();
void keyValueIterator();
+ void multimapKeyValueIterator();
+ void keyValueIteratorInEmptyMap();
void keys_values_uniqueKeys();
void qmultimap_specific();
@@ -70,11 +56,23 @@ private slots:
void equal_range();
void insert();
+ void insertMap();
void checkMostLeftNode();
void initializerList();
void testInsertWithHint();
void testInsertMultiWithHint();
void eraseValidIteratorOnSharedMap();
+ void removeElementsInMap();
+ void toStdMap();
+
+ void multiMapStoresInReverseInsertionOrder();
+
+ // Tests for deprecated APIs.
+#if QT_DEPRECATED_SINCE(6, 0)
+ void deprecatedInsertMulti();
+ void deprecatedIteratorApis();
+ void deprecatedInsert();
+#endif // QT_DEPRECATED_SINCE(6, 0)
};
struct IdentityTracker {
@@ -111,21 +109,22 @@ public:
int MyClass::count = 0;
typedef QMap<QString, MyClass> MyMap;
+typedef QMultiMap<QString, MyClass> MyMultiMap;
QDebug operator << (QDebug d, const MyClass &c) {
d << c.str;
return d;
}
-template <class KEY, class VALUE>
-void tst_QMap::sanityCheckTree(const QMap<KEY, VALUE> &m, int calledFromLine)
+template <class Map>
+void tst_QMap::sanityCheckTree(const Map &m, int calledFromLine)
{
QString possibleFrom;
possibleFrom.setNum(calledFromLine);
possibleFrom = "Called from line: " + possibleFrom;
int count = 0;
- typename QMap<KEY, VALUE>::const_iterator oldite = m.constBegin();
- for (typename QMap<KEY, VALUE>::const_iterator i = m.constBegin(); i != m.constEnd(); ++i) {
+ typename Map::const_iterator oldite = m.constBegin();
+ for (typename Map::const_iterator i = m.constBegin(); i != m.constEnd(); ++i) {
count++;
bool oldIteratorIsLarger = i.key() < oldite.key();
QVERIFY2(!oldIteratorIsLarger, possibleFrom.toUtf8());
@@ -173,13 +172,21 @@ void tst_QMap::count()
{
MyMap map;
MyMap map2( map );
- QCOMPARE( map.count(), 0 );
- QCOMPARE( map2.count(), 0 );
+ QCOMPARE( map.size(), 0 );
+ QCOMPARE( map2.size(), 0 );
QCOMPARE( MyClass::count, int(0) );
+ QCOMPARE(map.count("key"), 0);
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map2.size(), 0);
+ QVERIFY(!map.isDetached());
+ QVERIFY(!map2.isDetached());
// detach
map2["Hallo"] = MyClass( "Fritz" );
- QCOMPARE( map.count(), 0 );
- QCOMPARE( map2.count(), 1 );
+ QCOMPARE( map.size(), 0 );
+ QCOMPARE( map.size(), 0 );
+ QCOMPARE( map2.size(), 1 );
+ QCOMPARE( map2.size(), 1 );
+ QVERIFY(!map.isDetached());
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 1 );
#endif
@@ -189,11 +196,11 @@ void tst_QMap::count()
{
typedef QMap<QString, MyClass> Map;
Map map;
- QCOMPARE( map.count(), 0);
+ QCOMPARE( map.size(), 0);
map.insert( "Torben", MyClass("Weis") );
- QCOMPARE( map.count(), 1 );
+ QCOMPARE( map.size(), 1 );
map.insert( "Claudia", MyClass("Sorg") );
- QCOMPARE( map.count(), 2 );
+ QCOMPARE( map.size(), 2 );
map.insert( "Lars", MyClass("Linzbach") );
map.insert( "Matthias", MyClass("Ettrich") );
map.insert( "Sue", MyClass("Paludo") );
@@ -201,7 +208,7 @@ void tst_QMap::count()
map.insert( "Haavard", MyClass("Nord") );
map.insert( "Arnt", MyClass("Gulbrandsen") );
map.insert( "Paul", MyClass("Tvete") );
- QCOMPARE( map.count(), 9 );
+ QCOMPARE( map.size(), 9 );
map.insert( "Paul", MyClass("Tvete 1") );
map.insert( "Paul", MyClass("Tvete 2") );
map.insert( "Paul", MyClass("Tvete 3") );
@@ -209,69 +216,69 @@ void tst_QMap::count()
map.insert( "Paul", MyClass("Tvete 5") );
map.insert( "Paul", MyClass("Tvete 6") );
- QCOMPARE( map.count(), 9 );
+ QCOMPARE( map.size(), 9 );
QCOMPARE( map.count("Paul"), 1 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
Map map2( map );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.insert( "Kay", MyClass("Roemer") );
- QVERIFY( map2.count() == 10 );
- QVERIFY( map.count() == 9 );
+ QVERIFY( map2.size() == 10 );
+ QVERIFY( map.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 19 );
#endif
map2 = map;
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.insert( "Kay", MyClass("Roemer") );
- QVERIFY( map2.count() == 10 );
+ QVERIFY( map2.size() == 10 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 19 );
#endif
map2.clear();
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2 = map;
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 9 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 9 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map2.clear();
- QVERIFY( map.count() == 9 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 9 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 9 );
#endif
map.remove( "Lars" );
- QVERIFY( map.count() == 8 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 8 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 8 );
#endif
map.remove( "Mist" );
- QVERIFY( map.count() == 8 );
- QVERIFY( map2.count() == 0 );
+ QVERIFY( map.size() == 8 );
+ QVERIFY( map2.size() == 0 );
#ifndef Q_CC_SUN
QCOMPARE( MyClass::count, 8 );
#endif
@@ -285,22 +292,22 @@ void tst_QMap::count()
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 1 );
#endif
- QVERIFY( map.count() == 1 );
+ QVERIFY( map.size() == 1 );
(void)map["Torben"].str;
(void)map["Lars"].str;
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 2 );
#endif
- QVERIFY( map.count() == 2 );
+ QVERIFY( map.size() == 2 );
const Map& cmap = map;
(void)cmap["Depp"].str;
#ifndef Q_CC_SUN
QVERIFY( MyClass::count == 2 );
#endif
- QVERIFY( map.count() == 2 );
- QVERIFY( cmap.count() == 2 );
+ QVERIFY( map.size() == 2 );
+ QVERIFY( cmap.size() == 2 );
}
QCOMPARE( MyClass::count, 0 );
{
@@ -313,6 +320,45 @@ void tst_QMap::count()
QCOMPARE( MyClass::count, 0 );
}
QCOMPARE( MyClass::count, 0 );
+
+ {
+ QMultiMap<int, MyClass> map;
+ QMultiMap<int, MyClass> map2(map);
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map2.size(), 0);
+ QCOMPARE(MyClass::count, 0);
+ QCOMPARE(map.count(1), 0);
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map2.size(), 0);
+ QVERIFY(!map.isDetached());
+ QVERIFY(!map2.isDetached());
+
+ // detach
+ map2.insert(0, MyClass("value0"));
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map2.size(), 1);
+ QCOMPARE(map2.size(), 1);
+ QVERIFY(!map.isDetached());
+ QCOMPARE(MyClass::count, 1);
+
+ map2.insert(1, MyClass("value1"));
+ map2.insert(2, MyClass("value2"));
+ QCOMPARE(map2.size(), 3);
+ QCOMPARE(MyClass::count, 3);
+
+ map2.insert(0, MyClass("value0_1"));
+ map2.insert(0, MyClass("value0_2"));
+ QCOMPARE(map2.size(), 5);
+ QCOMPARE(map2.count(0), 3);
+ QCOMPARE(MyClass::count, 5);
+
+ map2.clear();
+ QCOMPARE(map2.size(), 0);
+ QCOMPARE(MyClass::count, 0);
+
+ }
+ QCOMPARE(MyClass::count, 0);
}
void tst_QMap::clear()
@@ -320,18 +366,40 @@ void tst_QMap::clear()
{
MyMap map;
map.clear();
- QVERIFY( map.isEmpty() );
+ QVERIFY(map.isEmpty());
+ QVERIFY(!map.isDetached());
map.insert( "key", MyClass( "value" ) );
+ QVERIFY(!map.isEmpty());
map.clear();
- QVERIFY( map.isEmpty() );
+ QVERIFY(map.isEmpty());
map.insert( "key0", MyClass( "value0" ) );
map.insert( "key0", MyClass( "value1" ) );
map.insert( "key1", MyClass( "value2" ) );
+ QVERIFY(!map.isEmpty());
map.clear();
sanityCheckTree(map, __LINE__);
- QVERIFY( map.isEmpty() );
+ QVERIFY(map.isEmpty());
}
- QCOMPARE( MyClass::count, int(0) );
+ QCOMPARE(MyClass::count, int(0));
+
+ {
+ MyMultiMap map;
+ map.clear();
+ QVERIFY(map.isEmpty());
+ QVERIFY(!map.isDetached());
+ map.insert( "key", MyClass( "value" ) );
+ QVERIFY(!map.isEmpty());
+ map.clear();
+ QVERIFY(map.isEmpty());
+ map.insert( "key0", MyClass( "value0" ) );
+ map.insert( "key0", MyClass( "value1" ) );
+ map.insert( "key1", MyClass( "value2" ) );
+ QVERIFY(!map.isEmpty());
+ map.clear();
+ sanityCheckTree(map, __LINE__);
+ QVERIFY(map.isEmpty());
+ }
+ QCOMPARE(MyClass::count, int(0));
}
void tst_QMap::beginEnd()
@@ -367,7 +435,12 @@ void tst_QMap::beginEnd()
// detach
map2.insert( "2", "c" );
QVERIFY( map.constBegin() == map.constBegin() );
- QVERIFY( map.constBegin() != map2.constBegin() );
+
+ // comparing iterators between two different std::map is UB (and raises an
+ // assertion failure with MSVC debug-mode iterators), so we compare the
+ // elements' addresses.
+ QVERIFY(&map.constBegin().key() != &map2.constBegin().key());
+ QVERIFY(&map.constBegin().value() != &map2.constBegin().value());
}
void tst_QMap::firstLast()
@@ -406,6 +479,7 @@ void tst_QMap::key()
QMap<QString, int> map1;
QCOMPARE(map1.key(1), QString());
QCOMPARE(map1.key(1, def), def);
+ QVERIFY(!map1.isDetached());
map1.insert("one", 1);
QCOMPARE(map1.key(1), QLatin1String("one"));
@@ -436,6 +510,7 @@ void tst_QMap::key()
QMap<int, QString> map2;
QCOMPARE(map2.key("one"), 0);
QCOMPARE(map2.key("one", def), def);
+ QVERIFY(!map2.isDetached());
map2.insert(1, "one");
QCOMPARE(map2.key("one"), 1);
@@ -467,6 +542,82 @@ void tst_QMap::key()
QCOMPARE(map2.key("zero"), 0);
QCOMPARE(map2.key("zero", def), 0);
}
+
+ {
+ int def = -1;
+ QMultiMap<int, QString> multiMap;
+ QCOMPARE(multiMap.key("value0"), 0);
+ QCOMPARE(multiMap.key("value0", def), def);
+ QVERIFY(!multiMap.isDetached());
+
+ multiMap.insert(1, "value1");
+ multiMap.insert(2, "value2");
+ multiMap.insert(1, "value1_1");
+
+ QCOMPARE(multiMap.key("value1"), 1);
+ QCOMPARE(multiMap.key("value1", def), 1);
+ QCOMPARE(multiMap.key("value1_1"), 1);
+ QCOMPARE(multiMap.key("value2"), 2);
+ QCOMPARE(multiMap.key("value3"), 0);
+ QCOMPARE(multiMap.key("value3", def), def);
+ }
+}
+
+void tst_QMap::value()
+{
+ const QString def = "default value";
+ {
+ QMap<int, QString> map;
+ QCOMPARE(map.value(1), QString());
+ QCOMPARE(map.value(1, def), def);
+ QVERIFY(!map.isDetached());
+
+ map.insert(1, "value1");
+ QCOMPARE(map.value(1), "value1");
+ QCOMPARE(map[1], "value1");
+ QCOMPARE(map.value(2), QString());
+ QCOMPARE(map.value(2, def), def);
+ QCOMPARE(map[2], QString());
+ QCOMPARE(map.size(), 2);
+
+ map.insert(2, "value2");
+ QCOMPARE(map.value(2), "value2");
+ QCOMPARE(map[2], "value2");
+
+ map.insert(1, "value3");
+ QCOMPARE(map.value(1), "value3");
+ QCOMPARE(map.value(1, def), "value3");
+ QCOMPARE(map[1], "value3");
+
+ const QMap<int, QString> constMap;
+ QVERIFY(!constMap.isDetached());
+ QCOMPARE(constMap.value(1, def), def);
+ QCOMPARE(constMap[1], QString());
+ QCOMPARE(constMap.size(), 0);
+ QVERIFY(!constMap.isDetached());
+ }
+ {
+ QMultiMap<int, QString> map;
+ QCOMPARE(map.value(1), QString());
+ QCOMPARE(map.value(1, def), def);
+ QVERIFY(!map.isDetached());
+
+ map.insert(1, "value1");
+ QCOMPARE(map.value(1), "value1");
+ QCOMPARE(map.value(2), QString());
+ QCOMPARE(map.value(2, def), def);
+
+ map.insert(2, "value2");
+ QCOMPARE(map.value(2), "value2");
+
+ map.insert(1, "value3");
+ // If multiple values exist, the most recently added is returned.
+ QCOMPARE(map.value(1), "value3");
+ QCOMPARE(map.value(1, def), "value3");
+
+ map.remove(1, "value3");
+ QCOMPARE(map.value(1), "value1");
+ }
}
void tst_QMap::swap()
@@ -489,16 +640,19 @@ void tst_QMap::operator_eq()
QMap<int, int> b;
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
a.insert(1,1);
b.insert(1,1);
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
a.insert(0,1);
b.insert(0,1);
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
// compare for inequality:
@@ -521,6 +675,7 @@ void tst_QMap::operator_eq()
QMap<QString, QString> b;
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
a.insert("Hello", "World");
@@ -529,6 +684,7 @@ void tst_QMap::operator_eq()
b.insert("Hello", "World");
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
a.insert("Goodbye", "cruel world");
@@ -545,6 +701,7 @@ void tst_QMap::operator_eq()
// empty keys and null keys match:
b.insert(QString(""), QString());
QVERIFY(a == b);
+ QCOMPARE(qHash(a), qHash(b));
QVERIFY(!(a != b));
}
@@ -559,64 +716,135 @@ void tst_QMap::operator_eq()
}
}
-void tst_QMap::empty()
+template <typename T>
+void emptyTestMethod()
{
- QMap<int, QString> map1;
+ T map;
- QVERIFY(map1.isEmpty());
+ QVERIFY(map.isEmpty());
+ QVERIFY(map.empty());
+ QVERIFY(!map.isDetached());
- map1.insert(1, "one");
- QVERIFY(!map1.isEmpty());
+ map.insert(1, "one");
+ QVERIFY(!map.isEmpty());
+ QVERIFY(!map.empty());
- map1.clear();
- QVERIFY(map1.isEmpty());
+ map.clear();
+ QVERIFY(map.isEmpty());
+ QVERIFY(map.empty());
+}
+void tst_QMap::empty()
+{
+ emptyTestMethod<QMap<int, QString>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ emptyTestMethod<QMultiMap<int, QString>>();
}
void tst_QMap::contains()
{
- QMap<int, QString> map1;
- int i;
+ {
+ QMap<int, QString> map1;
+ int i;
- map1.insert(1, "one");
- QVERIFY(map1.contains(1));
+ QVERIFY(!map1.contains(1));
+ QVERIFY(!map1.isDetached());
- for(i=2; i < 100; ++i)
- map1.insert(i, "teststring");
- for(i=99; i > 1; --i)
- QVERIFY(map1.contains(i));
+ map1.insert(1, "one");
+ QVERIFY(map1.contains(1));
- map1.remove(43);
- QVERIFY(!map1.contains(43));
+ for (i = 2; i < 100; ++i)
+ map1.insert(i, "teststring");
+ for (i = 99; i > 1; --i)
+ QVERIFY(map1.contains(i));
+
+ map1.remove(43);
+ QVERIFY(!map1.contains(43));
+ }
+
+ {
+ QMultiMap<int, QString> multiMap;
+ QVERIFY(!multiMap.contains(1));
+ QVERIFY(!multiMap.contains(1, "value1"));
+ QVERIFY(!multiMap.isDetached());
+
+ multiMap.insert(1, "value1");
+ multiMap.insert(2, "value2");
+ multiMap.insert(1, "value1_1");
+
+ QVERIFY(multiMap.contains(1));
+ QVERIFY(multiMap.contains(1, "value1"));
+ QVERIFY(multiMap.contains(1, "value1_1"));
+ QVERIFY(multiMap.contains(2));
+ QVERIFY(multiMap.contains(2, "value2"));
+ QVERIFY(!multiMap.contains(2, "invalid_value"));
+
+ QVERIFY(!multiMap.contains(3));
+ multiMap.insert(3, "value3");
+ QVERIFY(multiMap.contains(3));
+
+ multiMap.remove(3);
+ QVERIFY(!multiMap.contains(3));
+ }
}
void tst_QMap::find()
{
- QMap<int, QString> map1;
+ {
+ const QMap<int, QString> constMap;
+ QCOMPARE(constMap.find(1), constMap.end());
+ QVERIFY(!constMap.isDetached());
+
+ QMap<int, QString> map;
+ QCOMPARE(map.find(1), map.end());
+
+ map.insert(1, "value1");
+ map.insert(2, "value2");
+ map.insert(5, "value5");
+ map.insert(1, "value0");
+
+ QCOMPARE(map.find(1).value(), u"value0");
+ QCOMPARE(map.find(5).value(), u"value5");
+ QCOMPARE(map.find(2).value(), u"value2");
+ QCOMPARE(map.find(4), map.end());
+ }
+
+ const QMultiMap<int, QString> constMap;
+ QCOMPARE(constMap.find(1), constMap.end());
+ QCOMPARE(constMap.find(1, "value"), constMap.end());
+ QVERIFY(!constMap.isDetached());
+
+ QMultiMap<int, QString> map;
QString testString="Teststring %0";
QString compareString;
int i,count=0;
- QVERIFY(map1.find(1) == map1.end());
+ QCOMPARE(map.find(1), map.end());
+ QCOMPARE(map.find(1, "value1"), map.end());
- map1.insert(1,"Mensch");
- map1.insert(1,"Mayer");
- map1.insert(2,"Hej");
+ map.insert(1,"Mensch");
+ map.insert(1,"Mayer");
+ map.insert(2,"Hej");
- QCOMPARE(map1.find(1).value(), QLatin1String("Mayer"));
- QCOMPARE(map1.find(2).value(), QLatin1String("Hej"));
+ QCOMPARE(map.find(1).value(), QLatin1String("Mayer"));
+ QCOMPARE(map.find(2).value(), QLatin1String("Hej"));
+ QCOMPARE(map.find(1, "Mensch").value(), QLatin1String("Mensch"));
+ QCOMPARE(map.find(1, "Unknown Value"), map.end());
- for(i = 3; i < 10; ++i) {
+ for (i = 3; i < 10; ++i) {
compareString = testString.arg(i);
- map1.insertMulti(4, compareString);
- QCOMPARE(map1.count(4), i - 2);
+ map.insert(4, compareString);
+ QCOMPARE(map.count(4), i - 2);
}
- QMap<int, QString>::const_iterator it=map1.constFind(4);
+ QMultiMap<int, QString>::iterator it = map.find(4);
- for(i = 9; i > 2 && it != map1.constEnd() && it.key() == 4; --i) {
+ for (i = 9; i > 2 && it != map.end() && it.key() == 4; --i) {
compareString = testString.arg(i);
QVERIFY(it.value() == compareString);
+ QCOMPARE(map.find(4, compareString), it);
++it;
++count;
}
@@ -625,32 +853,53 @@ void tst_QMap::find()
void tst_QMap::constFind()
{
- QMap<int, QString> map1;
+ {
+ QMap<int, QString> map;
+ QCOMPARE(map.constFind(1), map.constEnd());
+ QVERIFY(!map.isDetached());
+
+ map.insert(1, "value1");
+ map.insert(2, "value2");
+ map.insert(5, "value5");
+ map.insert(1, "value0");
+
+ QCOMPARE(map.constFind(1).value(), QLatin1String("value0"));
+ QCOMPARE(map.constFind(5).value(), QLatin1String("value5"));
+ QCOMPARE(map.constFind(2).value(), QLatin1String("value2"));
+ QCOMPARE(map.constFind(4), map.constEnd());
+ }
+
+ QMultiMap<int, QString> map;
QString testString="Teststring %0";
QString compareString;
int i,count=0;
- QVERIFY(map1.constFind(1) == map1.constEnd());
+ QCOMPARE(map.constFind(1), map.constEnd());
+ QCOMPARE(map.constFind(1, "value"), map.constEnd());
+ QVERIFY(!map.isDetached());
- map1.insert(1,"Mensch");
- map1.insert(1,"Mayer");
- map1.insert(2,"Hej");
+ map.insert(1,"Mensch");
+ map.insert(1,"Mayer");
+ map.insert(2,"Hej");
- QVERIFY(map1.constFind(4) == map1.constEnd());
+ QVERIFY(map.constFind(4) == map.constEnd());
- QCOMPARE(map1.constFind(1).value(), QLatin1String("Mayer"));
- QCOMPARE(map1.constFind(2).value(), QLatin1String("Hej"));
+ QCOMPARE(map.constFind(1).value(), QLatin1String("Mayer"));
+ QCOMPARE(map.constFind(2).value(), QLatin1String("Hej"));
+ QCOMPARE(map.constFind(1, "Mensch").value(), QLatin1String("Mensch"));
+ QCOMPARE(map.constFind(1, "Invalid Value"), map.constEnd());
- for(i = 3; i < 10; ++i) {
+ for (i = 3; i < 10; ++i) {
compareString = testString.arg(i);
- map1.insertMulti(4, compareString);
+ map.insert(4, compareString);
}
- QMap<int, QString>::const_iterator it=map1.constFind(4);
+ QMultiMap<int, QString>::const_iterator it = map.constFind(4);
- for(i = 9; i > 2 && it != map1.constEnd() && it.key() == 4; --i) {
+ for (i = 9; i > 2 && it != map.constEnd() && it.key() == 4; --i) {
compareString = testString.arg(i);
QVERIFY(it.value() == compareString);
+ QCOMPARE(map.constFind(4, compareString), it);
++it;
++count;
}
@@ -659,58 +908,128 @@ void tst_QMap::constFind()
void tst_QMap::lowerUpperBound()
{
- QMap<int, QString> map1;
+ {
+ const QMap<int, QString> emptyConstMap;
+ QCOMPARE(emptyConstMap.lowerBound(1), emptyConstMap.constEnd());
+ QCOMPARE(emptyConstMap.upperBound(1), emptyConstMap.constEnd());
+ QVERIFY(!emptyConstMap.isDetached());
+
+ const QMap<int, QString> constMap { qMakePair(1, "one"),
+ qMakePair(5, "five"),
+ qMakePair(10, "ten") };
+
+ QCOMPARE(constMap.lowerBound(-1).key(), 1);
+ QCOMPARE(constMap.lowerBound(1).key(), 1);
+ QCOMPARE(constMap.lowerBound(3).key(), 5);
+ QCOMPARE(constMap.lowerBound(12), constMap.constEnd());
+
+ QCOMPARE(constMap.upperBound(-1).key(), 1);
+ QCOMPARE(constMap.upperBound(1).key(), 5);
+ QCOMPARE(constMap.upperBound(3).key(), 5);
+ QCOMPARE(constMap.upperBound(12), constMap.constEnd());
+
+ QMap<int, QString> map;
+
+ map.insert(1, "one");
+ map.insert(5, "five");
+ map.insert(10, "ten");
+ map.insert(3, "three");
+ map.insert(7, "seven");
+
+ QCOMPARE(map.lowerBound(0).key(), 1);
+ QCOMPARE(map.lowerBound(1).key(), 1);
+ QCOMPARE(map.lowerBound(2).key(), 3);
+ QCOMPARE(map.lowerBound(3).key(), 3);
+ QCOMPARE(map.lowerBound(4).key(), 5);
+ QCOMPARE(map.lowerBound(5).key(), 5);
+ QCOMPARE(map.lowerBound(6).key(), 7);
+ QCOMPARE(map.lowerBound(7).key(), 7);
+ QCOMPARE(map.lowerBound(10).key(), 10);
+ QCOMPARE(map.lowerBound(999), map.end());
+
+ QCOMPARE(map.upperBound(0).key(), 1);
+ QCOMPARE(map.upperBound(1).key(), 3);
+ QCOMPARE(map.upperBound(2).key(), 3);
+ QCOMPARE(map.upperBound(3).key(), 5);
+ QCOMPARE(map.upperBound(7).key(), 10);
+ QCOMPARE(map.upperBound(10), map.end());
+ QCOMPARE(map.upperBound(999), map.end());
+ }
+
+ const QMultiMap<int, QString> emptyConstMap;
+ QCOMPARE(emptyConstMap.lowerBound(1), emptyConstMap.constEnd());
+ QCOMPARE(emptyConstMap.upperBound(1), emptyConstMap.constEnd());
+ QVERIFY(!emptyConstMap.isDetached());
- map1.insert(1, "one");
- map1.insert(5, "five");
- map1.insert(10, "ten");
+ const QMultiMap<int, QString> constMap { qMakePair(1, "one"),
+ qMakePair(5, "five"),
+ qMakePair(10, "ten") };
+ QCOMPARE(constMap.lowerBound(-1).key(), 1);
+ QCOMPARE(constMap.lowerBound(1).key(), 1);
+ QCOMPARE(constMap.lowerBound(3).key(), 5);
+ QCOMPARE(constMap.lowerBound(12), constMap.constEnd());
+
+ QCOMPARE(constMap.upperBound(-1).key(), 1);
+ QCOMPARE(constMap.upperBound(1).key(), 5);
+ QCOMPARE(constMap.upperBound(3).key(), 5);
+ QCOMPARE(constMap.upperBound(12), constMap.constEnd());
+
+ QMultiMap<int, QString> map;
+
+ map.insert(1, "one");
+ map.insert(5, "five");
+ map.insert(10, "ten");
//Copied from documentation
- QCOMPARE(map1.upperBound(0).key(), 1); // returns iterator to (1, "one")
- QCOMPARE(map1.upperBound(1).key(), 5); // returns iterator to (5, "five")
- QCOMPARE(map1.upperBound(2).key(), 5); // returns iterator to (5, "five")
- QVERIFY(map1.upperBound(10) == map1.end()); // returns end()
- QVERIFY(map1.upperBound(999) == map1.end()); // returns end()
-
- QCOMPARE(map1.lowerBound(0).key(), 1); // returns iterator to (1, "one")
- QCOMPARE(map1.lowerBound(1).key(), 1); // returns iterator to (1, "one")
- QCOMPARE(map1.lowerBound(2).key(), 5); // returns iterator to (5, "five")
- QCOMPARE(map1.lowerBound(10).key(), 10); // returns iterator to (10, "ten")
- QVERIFY(map1.lowerBound(999) == map1.end()); // returns end()
-
- map1.insert(3, "three");
- map1.insert(7, "seven");
- map1.insertMulti(7, "seven_2");
-
- QCOMPARE(map1.upperBound(0).key(), 1);
- QCOMPARE(map1.upperBound(1).key(), 3);
- QCOMPARE(map1.upperBound(2).key(), 3);
- QCOMPARE(map1.upperBound(3).key(), 5);
- QCOMPARE(map1.upperBound(7).key(), 10);
- QVERIFY(map1.upperBound(10) == map1.end());
- QVERIFY(map1.upperBound(999) == map1.end());
-
- QCOMPARE(map1.lowerBound(0).key(), 1);
- QCOMPARE(map1.lowerBound(1).key(), 1);
- QCOMPARE(map1.lowerBound(2).key(), 3);
- QCOMPARE(map1.lowerBound(3).key(), 3);
- QCOMPARE(map1.lowerBound(4).key(), 5);
- QCOMPARE(map1.lowerBound(5).key(), 5);
- QCOMPARE(map1.lowerBound(6).key(), 7);
- QCOMPARE(map1.lowerBound(7).key(), 7);
- QCOMPARE(map1.lowerBound(6).value(), QLatin1String("seven_2"));
- QCOMPARE(map1.lowerBound(7).value(), QLatin1String("seven_2"));
- QCOMPARE((++map1.lowerBound(6)).value(), QLatin1String("seven"));
- QCOMPARE((++map1.lowerBound(7)).value(), QLatin1String("seven"));
- QCOMPARE(map1.lowerBound(10).key(), 10);
- QVERIFY(map1.lowerBound(999) == map1.end());
+ QCOMPARE(map.upperBound(0).key(), 1); // returns iterator to (1, "one")
+ QCOMPARE(map.upperBound(1).key(), 5); // returns iterator to (5, "five")
+ QCOMPARE(map.upperBound(2).key(), 5); // returns iterator to (5, "five")
+ QVERIFY(map.upperBound(10) == map.end()); // returns end()
+ QVERIFY(map.upperBound(999) == map.end()); // returns end()
+
+ QCOMPARE(map.lowerBound(0).key(), 1); // returns iterator to (1, "one")
+ QCOMPARE(map.lowerBound(1).key(), 1); // returns iterator to (1, "one")
+ QCOMPARE(map.lowerBound(2).key(), 5); // returns iterator to (5, "five")
+ QCOMPARE(map.lowerBound(10).key(), 10); // returns iterator to (10, "ten")
+ QVERIFY(map.lowerBound(999) == map.end()); // returns end()
+
+ map.insert(3, "three");
+ map.insert(7, "seven");
+ map.insert(7, "seven_2");
+
+ QCOMPARE(map.upperBound(0).key(), 1);
+ QCOMPARE(map.upperBound(1).key(), 3);
+ QCOMPARE(map.upperBound(2).key(), 3);
+ QCOMPARE(map.upperBound(3).key(), 5);
+ QCOMPARE(map.upperBound(7).key(), 10);
+ QVERIFY(map.upperBound(10) == map.end());
+ QVERIFY(map.upperBound(999) == map.end());
+
+ QCOMPARE(map.lowerBound(0).key(), 1);
+ QCOMPARE(map.lowerBound(1).key(), 1);
+ QCOMPARE(map.lowerBound(2).key(), 3);
+ QCOMPARE(map.lowerBound(3).key(), 3);
+ QCOMPARE(map.lowerBound(4).key(), 5);
+ QCOMPARE(map.lowerBound(5).key(), 5);
+ QCOMPARE(map.lowerBound(6).key(), 7);
+ QCOMPARE(map.lowerBound(7).key(), 7);
+ QCOMPARE(map.lowerBound(6).value(), QLatin1String("seven_2"));
+ QCOMPARE(map.lowerBound(7).value(), QLatin1String("seven_2"));
+ QCOMPARE((++map.lowerBound(6)).value(), QLatin1String("seven"));
+ QCOMPARE((++map.lowerBound(7)).value(), QLatin1String("seven"));
+ QCOMPARE(map.lowerBound(10).key(), 10);
+ QVERIFY(map.lowerBound(999) == map.end());
}
void tst_QMap::mergeCompare()
{
- QMap<int, QString> map1, map2, map3, map1b, map2b;
+ QMultiMap<int, QString> map1, map2, map3, map1b, map2b, map4;
+
+ // unite with an empty map does nothing
+ map1.unite(map2);
+ QVERIFY(!map1.isDetached());
map1.insert(1,"ett");
map1.insert(3,"tre");
@@ -740,18 +1059,43 @@ void tst_QMap::mergeCompare()
map3.insert(4, "fyra");
map3.insert(5, "fem");
- QVERIFY(map1 == map3);
+ QCOMPARE(map1, map3);
+
+ map4.unite(map3);
+ QCOMPARE(map4, map3);
}
void tst_QMap::take()
{
- QMap<int, QString> map;
+ {
+ QMap<int, QString> map;
+ QCOMPARE(map.take(1), QString());
+ QVERIFY(!map.isDetached());
- map.insert(2, "zwei");
- map.insert(3, "drei");
+ map.insert(2, "zwei");
+ map.insert(3, "drei");
- QCOMPARE(map.take(3), QLatin1String("drei"));
- QVERIFY(!map.contains(3));
+ QCOMPARE(map.take(3), QLatin1String("drei"));
+ QVERIFY(!map.contains(3));
+ }
+
+ {
+ QMultiMap<int, QString> multiMap;
+ QCOMPARE(multiMap.take(1), QString());
+ QVERIFY(!multiMap.isDetached());
+
+ multiMap.insert(0, "value0");
+ multiMap.insert(1, "value1");
+ multiMap.insert(0, "value0_1");
+ multiMap.insert(0, "value0_2");
+
+ // The most recently inserted value is returned
+ QCOMPARE(multiMap.take(0), u"value0_2");
+ QCOMPARE(multiMap.take(0), u"value0_1");
+ QCOMPARE(multiMap.take(0), u"value0");
+ QCOMPARE(multiMap.take(0), QString());
+ QVERIFY(!multiMap.contains(0));
+ }
}
void tst_QMap::iterators()
@@ -768,13 +1112,13 @@ void tst_QMap::iterators()
QMap<int, QString>::iterator stlIt = map.begin();
QCOMPARE(stlIt.value(), QLatin1String("Teststring 1"));
- stlIt+=5;
+ std::advance(stlIt, 5);
QCOMPARE(stlIt.value(), QLatin1String("Teststring 6"));
stlIt++;
QCOMPARE(stlIt.value(), QLatin1String("Teststring 7"));
- stlIt-=3;
+ std::advance(stlIt, -3);
QCOMPARE(stlIt.value(), QLatin1String("Teststring 4"));
stlIt--;
@@ -789,13 +1133,13 @@ void tst_QMap::iterators()
QMap<int, QString>::const_iterator cstlIt = map.constBegin();
QCOMPARE(cstlIt.value(), QLatin1String("Teststring 1"));
- cstlIt+=5;
+ std::advance(cstlIt, 5);
QCOMPARE(cstlIt.value(), QLatin1String("Teststring 6"));
cstlIt++;
QCOMPARE(cstlIt.value(), QLatin1String("Teststring 7"));
- cstlIt-=3;
+ std::advance(cstlIt, -3);
QCOMPARE(cstlIt.value(), QLatin1String("Teststring 4"));
cstlIt--;
@@ -831,14 +1175,125 @@ void tst_QMap::iterators()
}
}
+void tst_QMap::multimapIterators()
+{
+ QMultiMap<int, QString> map;
+ const QString testString = "Teststring %1-%2";
+
+ for (int i = 0; i < 5; ++i) {
+ // reverse order, because the last added is returned first.
+ for (int j = 4; j >= 0; --j)
+ map.insert(i, testString.arg(i).arg(j));
+ }
+
+ // STL-style iterators
+ auto stlIt = map.begin();
+ QCOMPARE(stlIt.value(), u"Teststring 0-0");
+
+ stlIt++;
+ QCOMPARE(stlIt.value(), u"Teststring 0-1");
+
+ std::advance(stlIt, 10);
+ QCOMPARE(stlIt.value(), u"Teststring 2-1");
+
+ std::advance(stlIt, -4);
+ QCOMPARE(stlIt.value(), u"Teststring 1-2");
+
+ stlIt--;
+ QCOMPARE(stlIt.value(), u"Teststring 1-1");
+
+ // STL-style const iterators
+ auto cstlIt = map.cbegin();
+ QCOMPARE(cstlIt.value(), u"Teststring 0-0");
+
+ cstlIt++;
+ QCOMPARE(cstlIt.value(), u"Teststring 0-1");
+
+ std::advance(cstlIt, 16);
+ QCOMPARE(cstlIt.value(), u"Teststring 3-2");
+
+ std::advance(cstlIt, -6);
+ QCOMPARE(cstlIt.value(), u"Teststring 2-1");
+
+ cstlIt--;
+ QCOMPARE(cstlIt.value(), u"Teststring 2-0");
+
+ // Java-style iterator
+ QMultiMapIterator javaIt(map);
+ int i = 0;
+ int j = 0;
+ while (javaIt.hasNext()) {
+ javaIt.next();
+ QCOMPARE(javaIt.value(), testString.arg(i).arg(j));
+ if (++j == 5) {
+ j = 0;
+ i++;
+ }
+ }
+
+ i = 4;
+ j = 4;
+ while (javaIt.hasPrevious()) {
+ javaIt.previous();
+ QCOMPARE(javaIt.value(), testString.arg(i).arg(j));
+ if (--j < 0) {
+ j = 4;
+ i--;
+ }
+ }
+}
+
+template <typename T>
+void iteratorsInEmptyMapTestMethod()
+{
+ T map;
+ using ConstIter = typename T::const_iterator;
+ ConstIter it1 = map.cbegin();
+ ConstIter it2 = map.constBegin();
+ QVERIFY(it1 == it2 && it2 == ConstIter());
+ QVERIFY(!map.isDetached());
+
+ ConstIter it3 = map.cend();
+ ConstIter it4 = map.constEnd();
+ QVERIFY(it3 == it4 && it4 == ConstIter());
+ QVERIFY(!map.isDetached());
+
+ // to call const overloads of begin() and end()
+ const T map2;
+ ConstIter it5 = map2.begin();
+ ConstIter it6 = map2.end();
+ QVERIFY(it5 == it6 && it6 == ConstIter());
+ QVERIFY(!map2.isDetached());
+
+ using Iter = typename T::iterator;
+ Iter it7 = map.begin();
+ Iter it8 = map.end();
+ QVERIFY(it7 == it8);
+}
+
+void tst_QMap::iteratorsInEmptyMap()
+{
+ iteratorsInEmptyMapTestMethod<QMap<int, int>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ iteratorsInEmptyMapTestMethod<QMultiMap<int, int>>();
+}
+
void tst_QMap::keyIterator()
{
QMap<int, int> map;
+ using KeyIterator = QMap<int, int>::key_iterator;
+ KeyIterator it1 = map.keyBegin();
+ KeyIterator it2 = map.keyEnd();
+ QVERIFY(it1 == it2 && it2 == KeyIterator());
+ QVERIFY(!map.isDetached());
+
for (int i = 0; i < 100; ++i)
map.insert(i, i*100);
- QMap<int, int>::key_iterator key_it = map.keyBegin();
+ KeyIterator key_it = map.keyBegin();
QMap<int, int>::const_iterator it = map.cbegin();
for (int i = 0; i < 100; ++i) {
QCOMPARE(*key_it, it.key());
@@ -859,8 +1314,48 @@ void tst_QMap::keyIterator()
QCOMPARE(std::count(map.keyBegin(), map.keyEnd(), 99), 1);
// DefaultConstructible test
- typedef QMap<int, int>::key_iterator keyIterator;
- Q_STATIC_ASSERT(std::is_default_constructible<keyIterator>::value);
+ static_assert(std::is_default_constructible<KeyIterator>::value);
+}
+
+void tst_QMap::multimapKeyIterator()
+{
+ QMultiMap<int, int> map;
+
+ using KeyIterator = QMultiMap<int, int>::key_iterator;
+ KeyIterator it1 = map.keyBegin();
+ KeyIterator it2 = map.keyEnd();
+ QVERIFY(it1 == it2 && it2 == KeyIterator());
+ QVERIFY(!map.isDetached());
+
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 4; j >= 0; --j)
+ map.insert(i, 100 * i + j);
+ }
+
+ KeyIterator keyIt = map.keyBegin();
+ QMultiMap<int, int>::const_iterator it = map.cbegin();
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 4; j >= 0; --j) {
+ QCOMPARE(*keyIt, it.key());
+ ++keyIt;
+ ++it;
+ }
+ }
+
+ keyIt = std::find(map.keyBegin(), map.keyEnd(), 3);
+ it = std::find(map.cbegin(), map.cend(), 3 * 100);
+
+ QVERIFY(keyIt != map.keyEnd());
+ QCOMPARE(*keyIt, it.key());
+ QCOMPARE(*(keyIt++), (it++).key());
+ QCOMPARE(*(keyIt--), (it--).key());
+ QCOMPARE(*(++keyIt), (++it).key());
+ QCOMPARE(*(--keyIt), (--it).key());
+
+ QCOMPARE(std::count(map.keyBegin(), map.keyEnd(), 2), 5);
+
+ // DefaultConstructible test
+ static_assert(std::is_default_constructible<KeyIterator>::value);
}
void tst_QMap::keyValueIterator()
@@ -880,6 +1375,12 @@ void tst_QMap::keyValueIterator()
entry_type pair(it.key(), it.value());
QCOMPARE(*key_value_it, pair);
+ QCOMPARE(key_value_it->first, pair.first);
+ QCOMPARE(key_value_it->second, pair.second);
+ QCOMPARE(&(*key_value_it).first, &it.key());
+ QCOMPARE(&key_value_it->first, &it.key());
+ QCOMPARE(&(*key_value_it).second, &it.value());
+ QCOMPARE(&key_value_it->second, &it.value());
++key_value_it;
++it;
}
@@ -916,32 +1417,168 @@ void tst_QMap::keyValueIterator()
QCOMPARE(std::count(map.constKeyValueBegin(), map.constKeyValueEnd(), entry_type(key, value)), 1);
}
+void tst_QMap::multimapKeyValueIterator()
+{
+ QMultiMap<int, int> map;
+ using EntryType = QMultiMap<int, int>::const_key_value_iterator::value_type;
+
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 4; j >= 0; --j)
+ map.insert(i, 100 * i + j);
+ }
+
+ auto keyValueIt = map.constKeyValueBegin();
+ auto it = map.cbegin();
+
+ for (int i = 0; i < map.size(); ++i) {
+ QVERIFY(keyValueIt != map.constKeyValueEnd());
+ QVERIFY(it != map.cend());
+
+ EntryType pair(it.key(), it.value());
+ QCOMPARE(*keyValueIt, pair);
+ QCOMPARE(keyValueIt->first, pair.first);
+ QCOMPARE(keyValueIt->second, pair.second);
+ ++keyValueIt;
+ ++it;
+ }
+
+ QVERIFY(keyValueIt == map.constKeyValueEnd());
+ QVERIFY(it == map.cend());
+
+ int key = 3;
+ int value = 100 * 3;
+ keyValueIt = std::find(map.constKeyValueBegin(), map.constKeyValueEnd(), EntryType(key, value));
+ it = std::find(map.cbegin(), map.cend(), value);
+
+ QVERIFY(keyValueIt != map.constKeyValueEnd());
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ ++it;
+ ++keyValueIt;
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ --it;
+ --keyValueIt;
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ std::advance(it, 5);
+ std::advance(keyValueIt, 5);
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ std::advance(it, -5);
+ std::advance(keyValueIt, -5);
+ QCOMPARE(*keyValueIt, EntryType(it.key(), it.value()));
+
+ key = 2;
+ value = 100 * 2 + 2;
+ auto cnt = std::count(map.constKeyValueBegin(), map.constKeyValueEnd(), EntryType(key, value));
+ QCOMPARE(cnt, 1);
+}
+
+template <typename T>
+void keyValueIteratorInEmptyMapTestMethod()
+{
+ T map;
+ using ConstKeyValueIter = typename T::const_key_value_iterator;
+
+ ConstKeyValueIter it1 = map.constKeyValueBegin();
+ ConstKeyValueIter it2 = map.constKeyValueEnd();
+ QVERIFY(it1 == it2 && it2 == ConstKeyValueIter());
+ QVERIFY(!map.isDetached());
+
+ const T map2;
+ ConstKeyValueIter it3 = map2.keyValueBegin();
+ ConstKeyValueIter it4 = map2.keyValueEnd();
+ QVERIFY(it3 == it4 && it4 == ConstKeyValueIter());
+ QVERIFY(!map2.isDetached());
+
+ using KeyValueIter = typename T::key_value_iterator;
+
+ KeyValueIter it5 = map.keyValueBegin();
+ KeyValueIter it6 = map.keyValueEnd();
+ QVERIFY(it5 == it6);
+}
+
+void tst_QMap::keyValueIteratorInEmptyMap()
+{
+ keyValueIteratorInEmptyMapTestMethod<QMap<int, int>>();
+ if (QTest::currentTestFailed())
+ return;
+
+ keyValueIteratorInEmptyMapTestMethod<QMultiMap<int, int>>();
+}
+
void tst_QMap::keys_values_uniqueKeys()
{
- QMap<QString, int> map;
- QVERIFY(map.uniqueKeys().isEmpty());
+ {
+ QMap<QString, int> map;
+ QVERIFY(map.keys().isEmpty());
+ QVERIFY(map.keys(1).isEmpty());
+ QVERIFY(map.values().isEmpty());
+ QVERIFY(!map.isDetached());
+
+ map.insert("one", 1);
+ QCOMPARE(map.keys(), QStringList({ "one" }));
+ QCOMPARE(map.keys(1), QStringList({ "one" }));
+ QCOMPARE(map.values(), QList<int>({ 1 }));
+
+ map.insert("two", 2);
+ QCOMPARE(map.keys(), QStringList({ "one", "two" }));
+ QCOMPARE(map.keys(1), QStringList({ "one" }));
+ QCOMPARE(map.values(), QList<int>({ 1, 2 }));
+
+ map.insert("three", 2);
+ QCOMPARE(map.keys(), QStringList({ "one", "three", "two" }));
+ QCOMPARE(map.keys(2), QStringList({ "three", "two" }));
+ QCOMPARE(map.values(), QList<int>({ 1, 2, 2 }));
+
+ map.insert("one", 0);
+ QCOMPARE(map.keys(), QStringList({ "one", "three", "two" }));
+ QCOMPARE(map.keys(1), QStringList());
+ QCOMPARE(map.keys(0), QStringList({ "one" }));
+ QCOMPARE(map.keys(2), QStringList({ "three", "two" }));
+ QCOMPARE(map.values(), QList<int>({ 0, 2, 2 }));
+ }
+
+ QMultiMap<QString, int> map;
QVERIFY(map.keys().isEmpty());
+ QVERIFY(map.keys(1).isEmpty());
+ QVERIFY(map.uniqueKeys().isEmpty());
QVERIFY(map.values().isEmpty());
+ QVERIFY(map.values("key").isEmpty());
+ QVERIFY(!map.isDetached());
- map.insertMulti("alpha", 1);
+ map.insert("alpha", 1);
QVERIFY(map.keys() == (QList<QString>() << "alpha"));
- QVERIFY(map.uniqueKeys() == map.keys());
QVERIFY(map.values() == (QList<int>() << 1));
+ QVERIFY(map.uniqueKeys() == QList<QString>({ "alpha" }));
- map.insertMulti("beta", -2);
+ map.insert("beta", -2);
QVERIFY(map.keys() == (QList<QString>() << "alpha" << "beta"));
- QVERIFY(map.keys() == map.uniqueKeys());
QVERIFY(map.values() == (QList<int>() << 1 << -2));
+ QVERIFY(map.uniqueKeys() == QList<QString>({ "alpha", "beta" }));
- map.insertMulti("alpha", 2);
- QVERIFY(map.uniqueKeys() == (QList<QString>() << "alpha" << "beta"));
+ map.insert("alpha", 2);
QVERIFY(map.keys() == (QList<QString>() << "alpha" << "alpha" << "beta"));
QVERIFY(map.values() == (QList<int>() << 2 << 1 << -2));
+ QVERIFY(map.uniqueKeys() == QList<QString>({ "alpha", "beta" }));
+ QVERIFY(map.values("alpha") == QList<int>({ 2, 1 }));
- map.insertMulti("beta", 4);
- QVERIFY(map.uniqueKeys() == (QList<QString>() << "alpha" << "beta"));
+ map.insert("beta", 4);
QVERIFY(map.keys() == (QList<QString>() << "alpha" << "alpha" << "beta" << "beta"));
QVERIFY(map.values() == (QList<int>() << 2 << 1 << 4 << -2));
+ QVERIFY(map.uniqueKeys() == QList<QString>({ "alpha", "beta" }));
+ QVERIFY(map.values("alpha") == QList<int>({ 2, 1 }));
+ QVERIFY(map.values("beta") == QList<int>({ 4, -2 }));
+
+ map.insert("gamma", 2);
+ QVERIFY(map.keys() == QList<QString>({ "alpha", "alpha", "beta", "beta", "gamma" }));
+ QVERIFY(map.values() == QList<int>({ 2, 1, 4, -2, 2 }));
+ QVERIFY(map.uniqueKeys() == QList<QString>({ "alpha", "beta", "gamma" }));
+ QVERIFY(map.values("alpha") == QList<int>({ 2, 1 }));
+ QVERIFY(map.values("beta") == QList<int>({ 4, -2 }));
+ QVERIFY(map.values("gamma") == QList<int>({ 2 }));
+ QVERIFY(map.keys(2) == QList<QString>({ "alpha", "gamma" }));
}
void tst_QMap::qmultimap_specific()
@@ -964,26 +1601,26 @@ void tst_QMap::qmultimap_specific()
}
QVERIFY(map1.contains(9, 99));
- QCOMPARE(map1.count(), 45);
+ QCOMPARE(map1.size(), 45);
map1.remove(9, 99);
QVERIFY(!map1.contains(9, 99));
- QCOMPARE(map1.count(), 44);
+ QCOMPARE(map1.size(), 44);
map1.remove(9, 99);
QVERIFY(!map1.contains(9, 99));
- QCOMPARE(map1.count(), 44);
+ QCOMPARE(map1.size(), 44);
map1.remove(1, 99);
- QCOMPARE(map1.count(), 44);
+ QCOMPARE(map1.size(), 44);
map1.insert(1, 99);
map1.insert(1, 99);
- QCOMPARE(map1.count(), 46);
+ QCOMPARE(map1.size(), 46);
map1.remove(1, 99);
- QCOMPARE(map1.count(), 44);
+ QCOMPARE(map1.size(), 44);
map1.remove(1, 99);
- QCOMPARE(map1.count(), 44);
+ QCOMPARE(map1.size(), 44);
{
QMultiMap<int, int>::const_iterator i = map1.constFind(1, 11);
@@ -1042,7 +1679,7 @@ void tst_QMap::qmultimap_specific()
map2.insert(42, 1);
map2.insert(10, 2);
map2.insert(48, 3);
- QCOMPARE(map1.count(), map2.count());
+ QCOMPARE(map1.size(), map2.size());
QVERIFY(map1.remove(42,5));
QVERIFY(map2.remove(42,5));
QVERIFY(map1 == map2);
@@ -1069,14 +1706,45 @@ void tst_QMap::const_shared_null()
void tst_QMap::equal_range()
{
- QMap<int, QString> map;
- const QMap<int, QString> &cmap = map;
+ {
+ const QMap<int, QString> constMap;
+ QCOMPARE(constMap.equal_range(1), qMakePair(constMap.constEnd(), constMap.constEnd()));
+ QVERIFY(!constMap.isDetached());
+
+ QMap<int, QString> map;
+ QCOMPARE(map.equal_range(1), qMakePair(map.end(), map.end()));
+
+ map.insert(1, "value1");
+ map.insert(5, "value5");
+ map.insert(1, "value0");
+
+ auto pair = map.equal_range(1);
+ QCOMPARE(pair.first.value(), "value0");
+ QCOMPARE(pair.second.value(), "value5");
+ auto b = map.find(1);
+ auto e = map.find(5);
+ QCOMPARE(pair, qMakePair(b, e));
+
+ pair = map.equal_range(3);
+ QCOMPARE(pair.first.value(), "value5");
+ QCOMPARE(pair.second.value(), "value5");
+ QCOMPARE(pair, qMakePair(e, e));
+
+ QCOMPARE(map.equal_range(10), qMakePair(map.end(), map.end()));
+ }
+
+ const QMultiMap<int, QString> constMap;
+ QCOMPARE(constMap.equal_range(1), qMakePair(constMap.constEnd(), constMap.constEnd()));
+ QVERIFY(!constMap.isDetached());
- QPair<QMap<int, QString>::iterator, QMap<int, QString>::iterator> result = map.equal_range(0);
+ QMultiMap<int, QString> map;
+ const QMultiMap<int, QString> &cmap = map;
+
+ QPair<QMultiMap<int, QString>::iterator, QMultiMap<int, QString>::iterator> result = map.equal_range(0);
QCOMPARE(result.first, map.end());
QCOMPARE(result.second, map.end());
- QPair<QMap<int, QString>::const_iterator, QMap<int, QString>::const_iterator> cresult = cmap.equal_range(0);
+ QPair<QMultiMap<int, QString>::const_iterator, QMultiMap<int, QString>::const_iterator> cresult = cmap.equal_range(0);
QCOMPARE(cresult.first, cmap.cend());
QCOMPARE(cresult.second, cmap.cend());
@@ -1133,7 +1801,7 @@ void tst_QMap::equal_range()
QCOMPARE(cresult.first, cmap.find(2));
QCOMPARE(cresult.second, cmap.find(4));
- map.insertMulti(1, "another one");
+ map.insert(1, "another one");
result = map.equal_range(1);
QCOMPARE(result.first, map.find(1));
@@ -1146,19 +1814,13 @@ void tst_QMap::equal_range()
QCOMPARE(map.count(1), 2);
}
-template <class T>
-const T &const_(const T &t)
-{
- return t;
-}
-
void tst_QMap::insert()
{
QMap<QString, float> map;
map.insert("cs/key1", 1);
map.insert("cs/key2", 2);
map.insert("cs/key1", 3);
- QCOMPARE(map.count(), 2);
+ QCOMPARE(map.size(), 2);
QMap<int, int> intMap;
for (int i = 0; i < 1000; ++i) {
@@ -1202,6 +1864,226 @@ void tst_QMap::insert()
}
}
+template <template <typename K, typename T> typename Map>
+void testDetachWhenInsert()
+{
+ const Map<int, int> referenceSource = {
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 }
+ };
+
+ const Map<int, int> referenceDestination = {
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 },
+ { 3, 3 }
+ };
+
+ // copy insertion of non-shared map
+ {
+ Map<int, int> source;
+ source.insert(0, 0);
+ source.insert(1, 1);
+ source.insert(2, 2);
+
+ Map<int, int> dest;
+ dest.insert(3, 3);
+ Map<int, int> destCopy = dest;
+
+ if constexpr (std::is_same_v<decltype(dest), QMap<int, int>>)
+ dest.insert(source); // QMap
+ else
+ dest.unite(source); // QMultiMap
+
+ QCOMPARE(source, referenceSource);
+ QCOMPARE(dest, referenceDestination);
+
+ QCOMPARE(destCopy.size(), 1); // unchanged
+ }
+
+ // copy insertion of shared map
+ {
+ Map<int, int> source;
+ source.insert(0, 0);
+ source.insert(1, 1);
+ source.insert(2, 2);
+ Map<int, int> sourceCopy = source;
+
+ Map<int, int> dest;
+ dest.insert(3, 3);
+ Map<int, int> destCopy = dest;
+
+ if constexpr (std::is_same_v<decltype(dest), QMap<int, int>>)
+ dest.insert(source); // QMap
+ else
+ dest.unite(source); // QMultiMap
+
+ QCOMPARE(source, referenceSource);
+ QCOMPARE(sourceCopy, referenceSource);
+
+ QCOMPARE(dest, referenceDestination);
+ QCOMPARE(destCopy.size(), 1); // unchanged
+ }
+
+ // move insertion of non-shared map
+ {
+ Map<int, int> source;
+ source.insert(0, 0);
+ source.insert(1, 1);
+ source.insert(2, 2);
+
+ Map<int, int> dest;
+ dest.insert(3, 3);
+ Map<int, int> destCopy = dest;
+
+ if constexpr (std::is_same_v<decltype(dest), QMap<int, int>>)
+ dest.insert(source); // QMap
+ else
+ dest.unite(source); // QMultiMap
+
+ QCOMPARE(dest, referenceDestination);
+ QCOMPARE(destCopy.size(), 1); // unchanged
+ }
+
+ // move insertion of shared map
+ {
+ Map<int, int> source;
+ source.insert(0, 0);
+ source.insert(1, 1);
+ source.insert(2, 2);
+ Map<int, int> sourceCopy = source;
+
+ Map<int, int> dest;
+ dest.insert(3, 3);
+ Map<int, int> destCopy = dest;
+
+ if constexpr (std::is_same_v<decltype(dest), QMap<int, int>>)
+ dest.insert(std::move(source)); // QMap
+ else
+ dest.unite(std::move(source)); // QMultiMap
+
+ QCOMPARE(sourceCopy, referenceSource);
+
+ QCOMPARE(dest, referenceDestination);
+ QCOMPARE(destCopy.size(), 1); // unchanged
+ }
+};
+
+void tst_QMap::insertMap()
+{
+ {
+ QMap<int, int> map1;
+ QMap<int, int> map2;
+ QVERIFY(map1.isEmpty());
+ QVERIFY(map2.isEmpty());
+
+ map1.insert(map2);
+ QVERIFY(map1.isEmpty());
+ QVERIFY(map2.isEmpty());
+ QVERIFY(!map1.isDetached());
+ QVERIFY(!map2.isDetached());
+ }
+ {
+ QMap<int, int> map;
+ map.insert(1, 1);
+ map.insert(2, 2);
+ map.insert(0, -1);
+
+ QMap<int, int> map2;
+ map2.insert(0, 0);
+ map2.insert(3, 3);
+ map2.insert(4, 4);
+
+ map.insert(map2);
+
+ QCOMPARE(map.size(), 5);
+ for (int i = 0; i < 5; ++i)
+ QCOMPARE(map[i], i);
+ }
+ {
+ QMap<int, int> map;
+ for (int i = 0; i < 10; ++i)
+ map.insert(i * 3, i);
+
+ QMap<int, int> map2;
+ for (int i = 0; i < 10; ++i)
+ map2.insert(i * 4, i);
+
+ map.insert(map2);
+
+ QCOMPARE(map.size(), 17);
+ for (int i = 0; i < 10; ++i) {
+ // i * 3 == i except for i = 4, 8
+ QCOMPARE(map[i * 3], (i && i % 4 == 0) ? i - (i / 4) : i);
+ QCOMPARE(map[i * 4], i);
+ }
+
+ auto it = map.cbegin();
+ int prev = it.key();
+ ++it;
+ for (auto end = map.cend(); it != end; ++it) {
+ QVERIFY(prev < it.key());
+ prev = it.key();
+ }
+ }
+ {
+ QMap<int, int> map;
+ map.insert(1, 1);
+
+ QMap<int, int> map2;
+
+ map.insert(map2);
+ QCOMPARE(map.size(), 1);
+ QCOMPARE(map[1], 1);
+ }
+ {
+ QMap<int, int> map;
+ QMap<int, int> map2;
+ map2.insert(1, 1);
+
+ map.insert(map2);
+ QCOMPARE(map.size(), 1);
+ QCOMPARE(map[1], 1);
+
+ QMap<int, int> map3;
+ map3.insert(std::move(map2));
+ QCOMPARE(map3, map);
+ }
+ {
+ QMap<int, int> map;
+ map.insert(0, 0);
+ map.insert(1, 1);
+ map.insert(2, 2);
+
+ // Test inserting into self, nothing should happen
+ map.insert(map);
+
+ QCOMPARE(map.size(), 3);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(map[i], i);
+ }
+ {
+ // Here we use a QMultiMap and insert that into QMap,
+ // since it has multiple values with the same key the
+ // ordering is undefined so we won't test that, but
+ // make sure this isn't adding multiple entries with the
+ // same key to the QMap.
+ QMap<int, int> map;
+ map.insert(0, 0);
+
+ QMap<int, int> map2;
+ map2.insert(0, 1);
+
+ map.insert(map2);
+
+ QCOMPARE(map.size(), 1);
+ }
+
+ testDetachWhenInsert<QMap>();
+ testDetachWhenInsert<QMultiMap>();
+}
+
void tst_QMap::checkMostLeftNode()
{
QMap<int, int> map;
@@ -1257,7 +2139,7 @@ void tst_QMap::checkMostLeftNode()
void tst_QMap::initializerList()
{
QMap<int, QString> map = {{1, "bar"}, {1, "hello"}, {2, "initializer_list"}};
- QCOMPARE(map.count(), 2);
+ QCOMPARE(map.size(), 2);
QCOMPARE(map[1], QString("hello"));
QCOMPARE(map[2], QString("initializer_list"));
@@ -1267,9 +2149,9 @@ void tst_QMap::initializerList()
// QCOMPARE(stdm[1], QString("bar"));
QMultiMap<QString, int> multiMap{{"il", 1}, {"il", 2}, {"il", 3}};
- QCOMPARE(multiMap.count(), 3);
+ QCOMPARE(multiMap.size(), 3);
QList<int> values = multiMap.values("il");
- QCOMPARE(values.count(), 3);
+ QCOMPARE(values.size(), 3);
QMap<int, int> emptyMap{};
QVERIFY(emptyMap.isEmpty());
@@ -1349,64 +2231,64 @@ void tst_QMap::testInsertWithHint()
void tst_QMap::testInsertMultiWithHint()
{
- QMap<int, int> map;
+ QMultiMap<int, int> map;
- map.insertMulti(map.end(), 64, 65);
- map[128] = 129;
- map[256] = 257;
+ map.insert(map.end(), 64, 65);
+ map.insert(128, 129);
+ map.insert(256, 257);
sanityCheckTree(map, __LINE__);
- map.insertMulti(map.end(), 512, 513);
- map.insertMulti(map.end(), 512, 513 * 2);
+ map.insert(map.end(), 512, 513);
+ map.insert(map.end(), 512, 513 * 2);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 5);
- map.insertMulti(map.end(), 256, 258); // wrong hint
+ map.insert(map.end(), 256, 258); // wrong hint
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 6);
- QMap<int, int>::iterator i = map.insertMulti(map.constBegin(), 256, 259); // wrong hint
+ QMultiMap<int, int>::iterator i = map.insert(map.constBegin(), 256, 259); // wrong hint
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 7);
- QMap<int, int>::iterator j = map.insertMulti(map.constBegin(), 69, 66);
+ QMultiMap<int, int>::iterator j = map.insert(map.constBegin(), 69, 66);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 8);
- j = map.insertMulti(j, 68, 259);
+ j = map.insert(j, 68, 259);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 9);
- j = map.insertMulti(j, 67, 67);
+ j = map.insert(j, 67, 67);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 10);
- i = map.insertMulti(i, 256, 259);
+ i = map.insert(i, 256, 259);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 11);
- i = map.insertMulti(i, 256, 260);
+ i = map.insert(i, 256, 260);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 12);
- map.insertMulti(i, 64, 67);
+ map.insert(i, 64, 67);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 13);
- map.insertMulti(map.constBegin(), 20, 20);
+ map.insert(map.constBegin(), 20, 20);
sanityCheckTree(map, __LINE__);
QCOMPARE(map.size(), 14);
}
void tst_QMap::eraseValidIteratorOnSharedMap()
{
- QMap<int, int> a, b;
+ QMultiMap<int, int> a, b;
a.insert(10, 10);
- a.insertMulti(10, 40);
- a.insertMulti(10, 25);
- a.insertMulti(10, 30);
+ a.insert(10, 40);
+ a.insert(10, 25);
+ a.insert(10, 30);
a.insert(20, 20);
- QMap<int, int>::iterator i = a.begin();
+ QMultiMap<int, int>::iterator i = a.begin();
while (i.value() != 25)
++i;
@@ -1426,12 +2308,12 @@ void tst_QMap::eraseValidIteratorOnSharedMap()
QCOMPARE(itemsWith10, 4);
// Border cases
- QMap <QString, QString> ms1, ms2, ms3;
+ QMultiMap <QString, QString> ms1, ms2, ms3;
+ ms1.insert("foo", "bar");
+ ms1.insert("foo", "quux");
ms1.insert("foo", "bar");
- ms1.insertMulti("foo", "quux");
- ms1.insertMulti("foo", "bar");
- QMap <QString, QString>::iterator si = ms1.begin();
+ QMultiMap <QString, QString>::iterator si = ms1.begin();
ms2 = ms1;
ms1.erase(si);
si = ms1.begin();
@@ -1454,5 +2336,314 @@ void tst_QMap::eraseValidIteratorOnSharedMap()
QCOMPARE(ms3.size(), 3);
}
+void tst_QMap::removeElementsInMap()
+{
+ // A class that causes an almost certain crash if its operator< is
+ // called on a destroyed object
+ struct SharedInt {
+ QSharedPointer<int> m_int;
+ explicit SharedInt(int i) : m_int(QSharedPointer<int>::create(i)) {}
+ bool operator<(const SharedInt &other) const { return *m_int < *other.m_int; }
+ };
+
+ {
+ QMap<int, int> map;
+ QCOMPARE(map.remove(1), 0);
+ QVERIFY(!map.isDetached());
+
+ auto cnt = map.removeIf([](QMap<int, int>::iterator) { return true; });
+ QCOMPARE(cnt, 0);
+ }
+ {
+ QMap<SharedInt, int> map {
+ { SharedInt(1), 1 },
+ { SharedInt(2), 2 },
+ { SharedInt(3), 3 },
+ { SharedInt(4), 4 },
+ { SharedInt(5), 5 },
+ };
+ QCOMPARE(map.size(), 5);
+
+ map.remove(SharedInt(1));
+ QCOMPARE(map.size(), 4);
+
+ map.remove(SharedInt(-1));
+ QCOMPARE(map.size(), 4);
+
+ QMap<SharedInt, int> map2 = map;
+ QCOMPARE(map.size(), 4);
+ QCOMPARE(map2.size(), 4);
+
+ map.remove(SharedInt(3));
+ QCOMPARE(map.size(), 3);
+ QCOMPARE(map2.size(), 4);
+
+ map.remove(SharedInt(-1));
+ QCOMPARE(map.size(), 3);
+ QCOMPARE(map2.size(), 4);
+
+ map = map2;
+ QCOMPARE(map.size(), 4);
+ QCOMPARE(map2.size(), 4);
+
+ map.remove(SharedInt(-1));
+ QCOMPARE(map.size(), 4);
+ QCOMPARE(map2.size(), 4);
+
+ map.remove(map.firstKey());
+ QCOMPARE(map.size(), 3);
+ QCOMPARE(map2.size(), 4);
+
+ map.remove(map.lastKey());
+ QCOMPARE(map.size(), 2);
+ QCOMPARE(map2.size(), 4);
+
+ map = map2;
+ QCOMPARE(map.size(), 4);
+ QCOMPARE(map2.size(), 4);
+
+ auto size = map.size();
+ for (auto it = map.begin(); it != map.end(); ) {
+ const auto oldIt = it++;
+ size -= map.remove(oldIt.key());
+ QCOMPARE(map.size(), size);
+ QCOMPARE(map2.size(), 4);
+ }
+
+ QCOMPARE(map.size(), 0);
+ QCOMPARE(map2.size(), 4);
+
+ auto cnt = map2.removeIf([](auto it) { return (*it % 2) == 0; });
+ QCOMPARE(cnt, 2);
+ QCOMPARE(map2.size(), 2);
+ }
+
+ {
+ QMultiMap<int, int> map;
+ QCOMPARE(map.remove(1), 0);
+ QVERIFY(!map.isDetached());
+
+ auto cnt = map.removeIf([](QMultiMap<int, int>::iterator) { return true; });
+ QCOMPARE(cnt, 0);
+ }
+ {
+ QMultiMap<SharedInt, int> multimap {
+ { SharedInt(1), 10 },
+ { SharedInt(1), 11 },
+ { SharedInt(2), 2 },
+ { SharedInt(3), 30 },
+ { SharedInt(3), 31 },
+ { SharedInt(3), 32 },
+ { SharedInt(4), 4 },
+ { SharedInt(5), 5 },
+ { SharedInt(6), 60 },
+ { SharedInt(6), 61 },
+ { SharedInt(6), 60 },
+ { SharedInt(6), 62 },
+ { SharedInt(6), 60 },
+ { SharedInt(7), 7 },
+ };
+
+ QCOMPARE(multimap.size(), 14);
+
+ multimap.remove(SharedInt(1));
+ QCOMPARE(multimap.size(), 12);
+
+ multimap.remove(SharedInt(-1));
+ QCOMPARE(multimap.size(), 12);
+
+ QMultiMap<SharedInt, int> multimap2 = multimap;
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(3));
+ QCOMPARE(multimap.size(), 9);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(4));
+ QCOMPARE(multimap.size(), 8);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(-1));
+ QCOMPARE(multimap.size(), 8);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap = multimap2;
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(-1));
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(6), 60);
+ QCOMPARE(multimap.size(), 9);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap = multimap2;
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(SharedInt(6), 62);
+ QCOMPARE(multimap.size(), 11);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(multimap.firstKey());
+ QCOMPARE(multimap.size(), 10);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap.remove(multimap.lastKey());
+ QCOMPARE(multimap.size(), 9);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap = multimap2;
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ auto itFor6 = multimap.find(SharedInt(6));
+ QVERIFY(itFor6 != multimap.end());
+ QCOMPARE(itFor6.value(), 60);
+ multimap.remove(itFor6.key(), itFor6.value());
+ QCOMPARE(multimap.size(), 9);
+ QCOMPARE(multimap2.size(), 12);
+
+ multimap = multimap2;
+ QCOMPARE(multimap.size(), 12);
+ QCOMPARE(multimap2.size(), 12);
+
+ auto size = multimap.size();
+ for (auto it = multimap.begin(); it != multimap.end();) {
+ const auto range = multimap.equal_range(it.key());
+ const auto oldIt = it;
+ it = range.second;
+ size -= multimap.remove(oldIt.key());
+ QCOMPARE(multimap.size(), size);
+ QCOMPARE(multimap2.size(), 12);
+ }
+
+ QCOMPARE(multimap.size(), 0);
+ QCOMPARE(multimap2.size(), 12);
+
+ auto cnt = multimap2.removeIf([](auto it) { return (*it % 2) == 0; });
+ QCOMPARE(cnt, 8);
+ QCOMPARE(multimap2.size(), 4);
+ }
+}
+
+template <typename QtMap, typename StdMap>
+void toStdMapTestMethod(const StdMap &expectedMap)
+{
+ QtMap map;
+ QVERIFY(map.isEmpty());
+ auto stdMap = map.toStdMap();
+ QVERIFY(stdMap.empty());
+ QVERIFY(!map.isDetached());
+
+ map.insert(1, "value1");
+ map.insert(2, "value2");
+ map.insert(3, "value3");
+ map.insert(1, "value0");
+
+ stdMap = map.toStdMap();
+ QCOMPARE(stdMap, expectedMap);
+}
+
+void tst_QMap::toStdMap()
+{
+ const std::map<int, QString> expectedMap { {1, "value0"}, {2, "value2"}, {3, "value3"} };
+ toStdMapTestMethod<QMap<int, QString>>(expectedMap);
+ if (QTest::currentTestFailed())
+ return;
+
+ const std::multimap<int, QString> expectedMultiMap {
+ {1, "value0"}, {1, "value1"}, {2, "value2"}, {3, "value3"} };
+ toStdMapTestMethod<QMultiMap<int, QString>>(expectedMultiMap);
+}
+
+void tst_QMap::multiMapStoresInReverseInsertionOrder()
+{
+ const QString strings[] = {
+ u"zero"_s,
+ u"null"_s,
+ u"nada"_s,
+ };
+ {
+ QMultiMap<int, QString> map;
+ for (const QString &string : strings)
+ map.insert(0, string);
+ auto printOnFailure = qScopeGuard([&] { qDebug() << map; });
+ QVERIFY(std::equal(map.begin(), map.end(),
+ std::rbegin(strings), std::rend(strings)));
+ printOnFailure.dismiss();
+ }
+}
+
+#if QT_DEPRECATED_SINCE(6, 0)
+void tst_QMap::deprecatedInsertMulti()
+{
+ QMultiMap<int, QString> referenceMap;
+ referenceMap.insert(1, "value1");
+ referenceMap.insert(2, "value2");
+ referenceMap.insert(3, "value3");
+ referenceMap.insert(1, "value1_2");
+ referenceMap.insert(referenceMap.find(2), 2, "value2_2");
+ referenceMap.insert(referenceMap.end(), 1, "value1_3");
+
+ QMultiMap<int, QString> deprecatedMap;
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
+ deprecatedMap.insertMulti(1, "value1");
+ deprecatedMap.insertMulti(2, "value2");
+ deprecatedMap.insertMulti(3, "value3");
+ deprecatedMap.insertMulti(1, "value1_2");
+ deprecatedMap.insertMulti(deprecatedMap.find(2), 2, "value2_2");
+ deprecatedMap.insertMulti(deprecatedMap.end(), 1, "value1_3");
+QT_WARNING_POP
+
+ QCOMPARE(deprecatedMap, referenceMap);
+}
+
+void tst_QMap::deprecatedIteratorApis()
+{
+ QMap<int, QString> map;
+ QString testString = "Teststring %1";
+ for (int i = 1; i < 100; ++i)
+ map.insert(i, testString.arg(i));
+
+ auto it = map.begin();
+ QCOMPARE(it.value(), QLatin1String("Teststring 1"));
+ QT_IGNORE_DEPRECATIONS(it += 5;)
+ QCOMPARE(it.value(), QLatin1String("Teststring 6"));
+ QT_IGNORE_DEPRECATIONS(it = it - 3;)
+ QCOMPARE(it.value(), QLatin1String("Teststring 3"));
+
+ auto cit = map.constBegin();
+ QCOMPARE(cit.value(), QLatin1String("Teststring 1"));
+ QT_IGNORE_DEPRECATIONS(cit += 5;)
+ QCOMPARE(cit.value(), QLatin1String("Teststring 6"));
+ QT_IGNORE_DEPRECATIONS(cit = cit - 3;)
+ QCOMPARE(cit.value(), QLatin1String("Teststring 3"));
+}
+
+void tst_QMap::deprecatedInsert()
+{
+ QMultiMap<int, QString> refMap;
+ refMap.insert(1, "value1");
+ refMap.insert(2, "value2");
+ refMap.insert(3, "value3");
+
+ QMultiMap<int, QString> depMap = refMap;
+
+ QMultiMap<int, QString> otherMap;
+ otherMap.insert(1, "value1_2");
+ otherMap.insert(3, "value3_2");
+ otherMap.insert(4, "value4");
+
+ refMap.unite(otherMap);
+ QT_IGNORE_DEPRECATIONS(depMap.insert(otherMap);)
+
+ QCOMPARE(refMap, depMap);
+}
+#endif // QT_DEPRECATED_SINCE(6, 0)
+
QTEST_APPLESS_MAIN(tst_QMap)
#include "tst_qmap.moc"
diff --git a/tests/auto/corelib/tools/qmargins/CMakeLists.txt b/tests/auto/corelib/tools/qmargins/CMakeLists.txt
new file mode 100644
index 0000000000..2e0ea797ff
--- /dev/null
+++ b/tests/auto/corelib/tools/qmargins/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmargins Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmargins LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qmargins
+ SOURCES
+ tst_qmargins.cpp
+)
diff --git a/tests/auto/corelib/tools/qmargins/qmargins.pro b/tests/auto/corelib/tools/qmargins/qmargins.pro
deleted file mode 100644
index 696f9374a2..0000000000
--- a/tests/auto/corelib/tools/qmargins/qmargins.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qmargins
-QT = core testlib
-SOURCES = tst_qmargins.cpp
diff --git a/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp b/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
index 2a35162ef0..2611f62f01 100644
--- a/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
+++ b/tests/auto/corelib/tools/qmargins/tst_qmargins.cpp
@@ -1,34 +1,40 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QMargins>
+#ifdef QVARIANT_H
+# error "This test requires qmargins.h to not include qvariant.h"
+#endif
+
+// don't assume <type_traits>
+template <typename T, typename U>
+constexpr inline bool my_is_same_v = false;
+template <typename T>
+constexpr inline bool my_is_same_v<T, T> = true;
+
+#define CHECK(cvref) \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QMargins cvref >())), int cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QMargins cvref >())), int cvref >); \
+ static_assert(my_is_same_v<decltype(get<2>(std::declval<QMargins cvref >())), int cvref >); \
+ static_assert(my_is_same_v<decltype(get<3>(std::declval<QMargins cvref >())), int cvref >); \
+ \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QMarginsF cvref >())), qreal cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QMarginsF cvref >())), qreal cvref >); \
+ static_assert(my_is_same_v<decltype(get<2>(std::declval<QMarginsF cvref >())), qreal cvref >); \
+ static_assert(my_is_same_v<decltype(get<3>(std::declval<QMarginsF cvref >())), qreal cvref >)
+
+CHECK(&);
+CHECK(const &);
+CHECK(&&);
+CHECK(const &&);
+
+#undef CHECK
+
+#include <QTest>
#include <qmargins.h>
+#include <array>
+
Q_DECLARE_METATYPE(QMargins)
class tst_QMargins : public QObject
@@ -36,12 +42,27 @@ class tst_QMargins : public QObject
Q_OBJECT
private slots:
void getSetCheck();
+#ifndef QT_NO_DATASTREAM
void dataStreamCheck();
+#endif
void operators();
+#ifndef QT_NO_DEBUG_STREAM
+ void debugStreamCheck();
+#endif
void getSetCheckF();
+#ifndef QT_NO_DATASTREAM
void dataStreamCheckF();
+#endif
void operatorsF();
+#ifndef QT_NO_DEBUG_STREAM
+ void debugStreamCheckF();
+#endif
+
+ void structuredBinding();
+
+ void toMarginsF_data();
+ void toMarginsF();
};
// Testing get/set functions
@@ -123,6 +144,19 @@ void tst_QMargins::operators()
QCOMPARE(-m3, QMargins(-10, -11, -12, -13));
}
+#ifndef QT_NO_DEBUG_STREAM
+// Testing QDebug operators
+void tst_QMargins::debugStreamCheck()
+{
+ QMargins m(10, 11, 12, 13);
+ const QString expected = "QMargins(10, 11, 12, 13)";
+ QString result;
+ QDebug(&result).nospace() << m;
+ QCOMPARE(result, expected);
+}
+#endif
+
+#ifndef QT_NO_DATASTREAM
// Testing QDataStream operators
void tst_QMargins::dataStreamCheck()
{
@@ -147,6 +181,7 @@ void tst_QMargins::dataStreamCheck()
QCOMPARE(marginsIn.bottom(), 6852);
}
}
+#endif
// Testing get/set functions
void tst_QMargins::getSetCheckF()
@@ -220,6 +255,7 @@ void tst_QMargins::operatorsF()
QCOMPARE(-m3, QMarginsF(-10.3, -11.4, -12.5, -13.6));
}
+#ifndef QT_NO_DATASTREAM
// Testing QDataStream operators
void tst_QMargins::dataStreamCheckF()
{
@@ -244,6 +280,102 @@ void tst_QMargins::dataStreamCheckF()
QCOMPARE(marginsIn.bottom(), 4.4);
}
}
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+// Testing QDebug operators
+void tst_QMargins::debugStreamCheckF()
+{
+ QMarginsF m(10.1, 11.2, 12.3, 13.4);
+ const QString expected = "QMarginsF(10.1, 11.2, 12.3, 13.4)";
+ QString result;
+ QDebug(&result).nospace() << m;
+ QCOMPARE(result, expected);
+}
+#endif
+
+void tst_QMargins::structuredBinding()
+{
+ {
+ QMargins m(1, 2, 3, 4);
+ auto [left, top, right, bottom] = m;
+ QCOMPARE(left, 1);
+ QCOMPARE(top, 2);
+ QCOMPARE(right, 3);
+ QCOMPARE(bottom, 4);
+ }
+ {
+ QMargins m(1, 2, 3, 4);
+ auto &[left, top, right, bottom] = m;
+ QCOMPARE(left, 1);
+ QCOMPARE(top, 2);
+ QCOMPARE(right, 3);
+ QCOMPARE(bottom, 4);
+
+ left = 10;
+ top = 20;
+ right = 30;
+ bottom = 40;
+ QCOMPARE(m.left(), 10);
+ QCOMPARE(m.top(), 20);
+ QCOMPARE(m.right(), 30);
+ QCOMPARE(m.bottom(), 40);
+ }
+ {
+ QMarginsF m(1.0, 2.0, 3.0, 4.0);
+ auto [left, top, right, bottom] = m;
+ QCOMPARE(left, 1.0);
+ QCOMPARE(top, 2.0);
+ QCOMPARE(right, 3.0);
+ QCOMPARE(bottom, 4.0);
+ }
+ {
+ QMarginsF m(1.0, 2.0, 3.0, 4.0);
+ auto &[left, top, right, bottom] = m;
+ QCOMPARE(left, 1.0);
+ QCOMPARE(top, 2.0);
+ QCOMPARE(right, 3.0);
+ QCOMPARE(bottom, 4.0);
+
+ left = 10.0;
+ top = 20.0;
+ right = 30.0;
+ bottom = 40.0;
+ QCOMPARE(m.left(), 10.0);
+ QCOMPARE(m.top(), 20.0);
+ QCOMPARE(m.right(), 30.0);
+ QCOMPARE(m.bottom(), 40.0);
+ }
+}
+
+void tst_QMargins::toMarginsF_data()
+{
+ QTest::addColumn<QMargins>("input");
+ QTest::addColumn<QMarginsF>("result");
+
+ auto row = [](int x1, int y1, int x2, int y2) {
+ QTest::addRow("(%d, %d, %d, %d)", x1, y1, x2, y2)
+ << QMargins(x1, y1, x2, y2) << QMarginsF(x1, y1, x2, y2);
+ };
+ constexpr std::array samples = {-1, 0, 1};
+ for (int x1 : samples) {
+ for (int y1 : samples) {
+ for (int x2 : samples) {
+ for (int y2 : samples) {
+ row(x1, y1, x2, y2);
+ }
+ }
+ }
+ }
+}
+
+void tst_QMargins::toMarginsF()
+{
+ QFETCH(const QMargins, input);
+ QFETCH(const QMarginsF, result);
+
+ QCOMPARE(input.toMarginsF(), result);
+}
QTEST_APPLESS_MAIN(tst_QMargins)
#include "tst_qmargins.moc"
diff --git a/tests/auto/corelib/tools/qmessageauthenticationcode/CMakeLists.txt b/tests/auto/corelib/tools/qmessageauthenticationcode/CMakeLists.txt
new file mode 100644
index 0000000000..a21481b7ba
--- /dev/null
+++ b/tests/auto/corelib/tools/qmessageauthenticationcode/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qmessageauthenticationcode Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qmessageauthenticationcode LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qmessageauthenticationcode
+ SOURCES
+ tst_qmessageauthenticationcode.cpp
+)
diff --git a/tests/auto/corelib/tools/qmessageauthenticationcode/qmessageauthenticationcode.pro b/tests/auto/corelib/tools/qmessageauthenticationcode/qmessageauthenticationcode.pro
deleted file mode 100644
index a62b702f22..0000000000
--- a/tests/auto/corelib/tools/qmessageauthenticationcode/qmessageauthenticationcode.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qmessageauthenticationcode
-QT = core testlib
-SOURCES = tst_qmessageauthenticationcode.cpp
-
diff --git a/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp b/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp
index 2f8052fd4a..9e94ad77e9 100644
--- a/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp
+++ b/tests/auto/corelib/tools/qmessageauthenticationcode/tst_qmessageauthenticationcode.cpp
@@ -1,47 +1,75 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
-** 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) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QCoreApplication>
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QCryptographicHash>
+#include <QMessageAuthenticationCode>
+#include <QBuffer>
class tst_QMessageAuthenticationCode : public QObject
{
Q_OBJECT
private slots:
+ void repeated_setKey_data();
+ void repeated_setKey();
void result_data();
void result();
void result_incremental_data();
void result_incremental();
+ void addData_overloads_data();
+ void addData_overloads();
+ void move();
+ void swap();
};
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
+void tst_QMessageAuthenticationCode::repeated_setKey_data()
+{
+ using A = QCryptographicHash::Algorithm;
+ QTest::addColumn<A>("algo");
+
+ const auto me = QMetaEnum::fromType<A>();
+ for (int i = 0, value; (value = me.value(i)) != -1; ++i)
+ QTest::addRow("%s", me.key(i)) << A(value);
+}
+
+void tst_QMessageAuthenticationCode::repeated_setKey()
+{
+ QFETCH(const QCryptographicHash::Algorithm, algo);
+
+ if (!QCryptographicHash::supportsAlgorithm(algo))
+ QSKIP("QCryptographicHash doesn't support this algorithm");
+
+ // GIVEN: two long keys, so we're sure the key needs to be hashed in order
+ // to fit into the hash algorithm's block
+
+ static const QByteArray key1(1024, 'a');
+ static const QByteArray key2(2048, 'b');
+
+ // WHEN: processing the same message
+
+ QMessageAuthenticationCode macX(algo);
+ QMessageAuthenticationCode mac1(algo, key1);
+ QMessageAuthenticationCode mac2(algo, key2);
+
+ const auto check = [](QMessageAuthenticationCode &mac) {
+ mac.addData("This is nonsense, ignore it, please.");
+ return mac.result();
+ };
+
+ macX.setKey(key1);
+ QCOMPARE(check(macX), check(mac1));
+
+ // THEN: the result does not depend on whether a new QMAC instance was used
+ // or an old one re-used (iow: setKey() reset()s)
+
+ macX.setKey(key2);
+ QCOMPARE(check(macX), check(mac2));
+}
+
void tst_QMessageAuthenticationCode::result_data()
{
QTest::addColumn<QCryptographicHash::Algorithm>("algo");
@@ -62,6 +90,15 @@ void tst_QMessageAuthenticationCode::result_data()
<< QByteArray()
<< QByteArray()
<< QByteArray::fromHex("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad");
+ QTest::newRow("sha384-empty") << QCryptographicHash::Sha384 << QByteArray() << QByteArray()
+ << QByteArray::fromHex(
+ "6c1f2ee938fad2e24bd91298474382ca218c75db3d83e114b3d43"
+ "67776d14d3551289e75e8209cd4b792302840234adc");
+ QTest::newRow("sha512-empty")
+ << QCryptographicHash::Sha512 << QByteArray() << QByteArray()
+ << QByteArray::fromHex(
+ "b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b"
+ "327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47");
// Some not-empty
QTest::newRow("md5") << QCryptographicHash::Md5
@@ -76,6 +113,17 @@ void tst_QMessageAuthenticationCode::result_data()
<< QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8");
+ QTest::newRow("sha384") << QCryptographicHash::Sha384 << QByteArray("key")
+ << QByteArray("The quick brown fox jumps over the lazy dog")
+ << QByteArray::fromHex(
+ "d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae"
+ "50700582a96cf35e1e554995fe4e03381c237");
+ QTest::newRow("sha512")
+ << QCryptographicHash::Sha512 << QByteArray("key")
+ << QByteArray("The quick brown fox jumps over the lazy dog")
+ << QByteArray::fromHex(
+ "b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f"
+ "7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a");
// Some from rfc-2104
QTest::newRow("rfc-md5-1") << QCryptographicHash::Md5
@@ -99,11 +147,13 @@ void tst_QMessageAuthenticationCode::result()
QFETCH(QByteArray, message);
QFETCH(QByteArray, code);
- QMessageAuthenticationCode mac(algo);
- mac.setKey(key);
+ QMessageAuthenticationCode mac(algo, key);
mac.addData(message);
- QByteArray result = mac.result();
+ QByteArrayView resultView = mac.resultView();
+
+ QCOMPARE(resultView, code);
+ const auto result = QMessageAuthenticationCode::hash(message, key, algo);
QCOMPARE(result, code);
}
@@ -119,20 +169,98 @@ void tst_QMessageAuthenticationCode::result_incremental()
QFETCH(QByteArray, message);
QFETCH(QByteArray, code);
- int index = message.length() / 2;
+ int index = message.size() / 2;
QByteArray leftPart(message.mid(0, index));
QByteArray rightPart(message.mid(index));
QCOMPARE(leftPart + rightPart, message);
- QMessageAuthenticationCode mac(algo);
- mac.setKey(key);
+ QMessageAuthenticationCode mac(algo, key);
mac.addData(leftPart);
mac.addData(rightPart);
- QByteArray result = mac.result();
+ QByteArrayView result = mac.resultView();
QCOMPARE(result, code);
}
+void tst_QMessageAuthenticationCode::addData_overloads_data()
+{
+ result_data();
+}
+
+void tst_QMessageAuthenticationCode::addData_overloads()
+{
+ QFETCH(QCryptographicHash::Algorithm, algo);
+ QFETCH(QByteArray, key);
+ QFETCH(QByteArray, message);
+ QFETCH(QByteArray, code);
+
+ // overload using const char* and length
+ {
+ QMessageAuthenticationCode mac(algo);
+ mac.setKey(key);
+ mac.addData(message.constData(), message.size());
+ QByteArrayView result = mac.resultView();
+
+ QCOMPARE(result, code);
+ }
+
+ // overload using QIODevice
+ {
+ QBuffer buffer(&message);
+ buffer.open(QIODevice::ReadOnly);
+ QMessageAuthenticationCode mac(algo);
+ mac.setKey(key);
+ QVERIFY(mac.addData(&buffer));
+ QByteArrayView result = mac.resultView();
+ buffer.close();
+
+ QCOMPARE(result, code);
+ }
+}
+
+void tst_QMessageAuthenticationCode::move()
+{
+ const QByteArray key = "123";
+
+ QMessageAuthenticationCode src(QCryptographicHash::Sha1, key);
+ src.addData("a");
+
+ // move constructor
+ auto intermediary = std::move(src);
+ intermediary.addData("b");
+
+ // move assign operator
+ QMessageAuthenticationCode dst(QCryptographicHash::Sha256, key);
+ dst.addData("no effect on the end result");
+ dst = std::move(intermediary);
+ dst.addData("c");
+
+ QCOMPARE(dst.resultView(),
+ QMessageAuthenticationCode::hash("abc", key, QCryptographicHash::Sha1));
+}
+
+void tst_QMessageAuthenticationCode::swap()
+{
+ const QByteArray key1 = "123";
+ const QByteArray key2 = "abcdefg";
+
+ QMessageAuthenticationCode mac1(QCryptographicHash::Sha1, key1);
+ QMessageAuthenticationCode mac2(QCryptographicHash::Sha256, key2);
+
+ mac1.addData("da");
+ mac2.addData("te");
+
+ mac1.swap(mac2);
+
+ mac2.addData("ta");
+ mac1.addData("st");
+
+ QCOMPARE(mac2.resultView(),
+ QMessageAuthenticationCode::hash("data", key1, QCryptographicHash::Sha1));
+ QCOMPARE(mac1.resultView(),
+ QMessageAuthenticationCode::hash("test", key2, QCryptographicHash::Sha256));
+}
+
QTEST_MAIN(tst_QMessageAuthenticationCode)
#include "tst_qmessageauthenticationcode.moc"
diff --git a/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt b/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt
new file mode 100644
index 0000000000..d0205cfa15
--- /dev/null
+++ b/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qoffsetstringarray Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qoffsetstringarray LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qoffsetstringarray
+ SOURCES
+ tst_qoffsetstringarray.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
+
+if (CLANG)
+ target_compile_options(tst_qoffsetstringarray
+ PUBLIC -fbracket-depth=512)
+elseif (GCC)
+ # fconstexpr-depth= defaults to 512
+endif()
diff --git a/tests/auto/corelib/tools/qoffsetstringarray/qoffsetstringarray.pro b/tests/auto/corelib/tools/qoffsetstringarray/qoffsetstringarray.pro
deleted file mode 100644
index c8e6a8e05a..0000000000
--- a/tests/auto/corelib/tools/qoffsetstringarray/qoffsetstringarray.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qoffsetstringarray
-QT = core testlib core-private
-CONFIG += c++11
-CONFIG += strict_c++
-SOURCES = $$PWD/tst_qoffsetstringarray.cpp
diff --git a/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp b/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp
index dfa0450b18..dbb24e7af4 100644
--- a/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp
+++ b/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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>
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <private/qoffsetstringarray_p.h>
@@ -38,6 +13,7 @@ class tst_QOffsetStringArray : public QObject
private slots:
void init();
void access();
+ void contains();
};
@@ -46,8 +22,7 @@ constexpr const auto messages = qOffsetStringArray(
"level - 1",
"level - 2",
"level - 3",
- "level - 4",
- ""
+ "level - 4"
);
constexpr const auto messages257 = qOffsetStringArray(
@@ -90,19 +65,17 @@ constexpr const auto messagesBigOffsets = qOffsetStringArray(
void tst_QOffsetStringArray::init()
{
- static_assert(messages.sizeString == 51, "message.sizeString");
- static_assert(messages.sizeOffsets == 6, "message.sizeOffsets");
- static_assert(std::is_same<decltype(messages)::Type, quint8>::value, "messages::Type != quint8");
-
- static_assert(messages257.sizeOffsets == 257, "messages257.sizeOffsets");
- static_assert(messages257.sizeString == 260, "messages257.sizeString");
- static_assert(std::is_same<decltype(messages257)::Type, quint16>::value,
- "messages257::Type != quint16");
-
- static_assert(messagesBigOffsets.sizeOffsets == 4, "messagesBigOffsets.sizeOffsets");
- static_assert(messagesBigOffsets.sizeString == 364, "messagesBigOffsets.sizeString");
- static_assert(std::is_same<decltype(messagesBigOffsets)::Type, quint16>::value,
- "messagesBigOffsets::Type != quint16");
+ static_assert(messages.m_string.size() == 50);
+ static_assert(messages.m_offsets.size() == 6);
+ static_assert(std::is_same_v<decltype(messages.m_offsets)::value_type, quint8>);
+
+ static_assert(messages257.m_offsets.size() == 258);
+ static_assert(messages257.m_string.size() == 260);
+ static_assert(std::is_same_v<decltype(messages257.m_offsets)::value_type, quint16>);
+
+ static_assert(messagesBigOffsets.m_offsets.size() == 5);
+ static_assert(messagesBigOffsets.m_string.size() == 364);
+ static_assert(std::is_same_v<decltype(messagesBigOffsets.m_offsets)::value_type, quint16>);
}
void tst_QOffsetStringArray::access()
@@ -112,10 +85,21 @@ void tst_QOffsetStringArray::access()
QCOMPARE(messages[2], "level - 2");
QCOMPARE(messages[3], "level - 3");
QCOMPARE(messages[4], "level - 4");
+ // out of bounds returns empty strings:
QCOMPARE(messages[5], "");
QCOMPARE(messages[6], "");
}
+void tst_QOffsetStringArray::contains()
+{
+ QVERIFY(!messages.contains(""));
+ QVERIFY( messages.contains("level - 0"));
+ std::string l2 = "level - 2"; // make sure we don't compare pointer values
+ QVERIFY( messages.contains(l2));
+ QByteArray L4 = "Level - 4";
+ QVERIFY( messages.contains(L4, Qt::CaseInsensitive));
+ QVERIFY(!messages.contains(L4, Qt::CaseSensitive));
+}
QTEST_APPLESS_MAIN(tst_QOffsetStringArray)
#include "tst_qoffsetstringarray.moc"
diff --git a/tests/auto/corelib/tools/qpair/CMakeLists.txt b/tests/auto/corelib/tools/qpair/CMakeLists.txt
new file mode 100644
index 0000000000..2dd048e015
--- /dev/null
+++ b/tests/auto/corelib/tools/qpair/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qpair Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qpair LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qpair
+ SOURCES
+ tst_qpair.cpp
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/qpair/qpair.pro b/tests/auto/corelib/tools/qpair/qpair.pro
deleted file mode 100644
index d684a24a57..0000000000
--- a/tests/auto/corelib/tools/qpair/qpair.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qpair
-QT = core testlib
-SOURCES = tst_qpair.cpp
-
-# Force C++17 if available (needed due to Q_COMPILER_DEDUCTION_GUIDES)
-contains(QT_CONFIG, c++1z): CONFIG += c++1z
diff --git a/tests/auto/corelib/tools/qpair/tst_qpair.cpp b/tests/auto/corelib/tools/qpair/tst_qpair.cpp
index 3c972329bc..0c9d87bb01 100644
--- a/tests/auto/corelib/tools/qpair/tst_qpair.cpp
+++ b/tests/auto/corelib/tools/qpair/tst_qpair.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 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>
+// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <QPair>
#include <QSize>
@@ -36,18 +11,19 @@ class tst_QPair : public QObject
Q_OBJECT
private Q_SLOTS:
void pairOfReferences();
+ void structuredBindings();
void testConstexpr();
void testConversions();
void taskQTBUG_48780_pairContainingCArray();
- void testDeducationRules();
+ void testDeductionRules();
};
-class C { C() {} char _[4]; };
-class M { M() {} char _[4]; };
-class P { char _[4]; };
+class C { C() {} ~C() {} Q_DECL_UNUSED_MEMBER char _[4]; };
+class M { M() {} Q_DECL_UNUSED_MEMBER char _[4]; };
+class P { Q_DECL_UNUSED_MEMBER char _[4]; };
QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(M, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(M, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
@@ -62,35 +38,34 @@ typedef QPair<P,C> QPairPC;
typedef QPair<P,M> QPairPM;
typedef QPair<P,P> QPairPP;
-Q_STATIC_ASSERT( QTypeInfo<QPairCC>::isComplex);
-Q_STATIC_ASSERT( QTypeInfo<QPairCC>::isStatic );
+static_assert( QTypeInfo<QPairCC>::isComplex);
+static_assert( !QTypeInfo<QPairCC>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairCM>::isComplex);
-Q_STATIC_ASSERT( QTypeInfo<QPairCM>::isStatic );
+static_assert( QTypeInfo<QPairCM>::isComplex);
+static_assert( !QTypeInfo<QPairCM>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairCP>::isComplex);
-Q_STATIC_ASSERT( QTypeInfo<QPairCP>::isStatic );
+static_assert( QTypeInfo<QPairCP>::isComplex);
+static_assert( !QTypeInfo<QPairCP>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairMC>::isComplex);
-Q_STATIC_ASSERT( QTypeInfo<QPairMC>::isStatic );
+static_assert( QTypeInfo<QPairMC>::isComplex);
+static_assert( !QTypeInfo<QPairMC>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairMM>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<QPairMM>::isStatic );
+static_assert( QTypeInfo<QPairMM>::isComplex);
+static_assert( QTypeInfo<QPairMM>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairMP>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<QPairMP>::isStatic );
+static_assert( QTypeInfo<QPairMP>::isComplex);
+static_assert( QTypeInfo<QPairMP>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairPC>::isComplex);
-Q_STATIC_ASSERT( QTypeInfo<QPairPC>::isStatic );
+static_assert( QTypeInfo<QPairPC>::isComplex);
+static_assert( !QTypeInfo<QPairPC>::isRelocatable );
-Q_STATIC_ASSERT( QTypeInfo<QPairPM>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<QPairPM>::isStatic );
+static_assert( QTypeInfo<QPairPM>::isComplex);
+static_assert( QTypeInfo<QPairPM>::isRelocatable );
-Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isStatic );
+static_assert(!QTypeInfo<QPairPP>::isComplex);
+static_assert( QTypeInfo<QPairPP>::isRelocatable );
-Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isDummy );
-Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isPointer);
+static_assert(!std::is_pointer_v<QPairPP>);
void tst_QPair::pairOfReferences()
@@ -122,17 +97,67 @@ void tst_QPair::pairOfReferences()
QCOMPARE(p.second, QLatin1String("World"));
}
+void tst_QPair::structuredBindings()
+{
+ using PV = QPair<int, QString>;
+ using PR = QPair<int&, const QString&>;
+
+ {
+ PV pv = {42, "Hello"};
+ PR pr = {pv.first, pv.second};
+
+ auto [fv, sv] = pv;
+
+ fv = 24;
+ sv = "World";
+ QCOMPARE(fv, 24);
+ QCOMPARE(sv, "World");
+ QCOMPARE(pv.first, 42);
+ QCOMPARE(pv.second, "Hello");
+
+ auto [fr, sr] = pr;
+
+ fr = 2424;
+ // sr = "World"; // const
+ QCOMPARE(fr, 2424);
+ QCOMPARE(pv.first, 2424);
+ }
+
+ {
+ PV pv = {42, "Hello"};
+ PR pr = {pv.first, pv.second};
+
+ auto& [fv, sv] = pv;
+
+ fv = 24;
+ sv = "World";
+ QCOMPARE(fv, 24);
+ QCOMPARE(sv, "World");
+ QCOMPARE(pv.first, 24);
+ QCOMPARE(pv.second, "World");
+
+ auto& [fr, sr] = pr;
+
+ fr = 4242;
+ //sr = "2World"; // const
+
+ QCOMPARE(fr, 4242);
+ QCOMPARE(pr.first, 4242);
+ QCOMPARE(pv.first, 4242);
+ }
+}
+
void tst_QPair::testConstexpr()
{
- Q_CONSTEXPR QPair<int, double> pID = qMakePair(0, 0.0);
+ constexpr QPair<int, double> pID = qMakePair(0, 0.0);
Q_UNUSED(pID);
- Q_CONSTEXPR QPair<double, double> pDD = qMakePair(0.0, 0.0);
- Q_CONSTEXPR QPair<double, double> pDD2 = qMakePair(0, 0.0); // involes (rvalue) conversion ctor
- Q_CONSTEXPR bool equal = pDD2 == pDD;
+ constexpr QPair<double, double> pDD = qMakePair(0.0, 0.0);
+ constexpr QPair<double, double> pDD2 = qMakePair(0, 0.0); // involes (rvalue) conversion ctor
+ constexpr bool equal = pDD2 == pDD;
QVERIFY(equal);
- Q_CONSTEXPR QPair<QSize, int> pSI = qMakePair(QSize(4, 5), 6);
+ constexpr QPair<QSize, int> pSI = qMakePair(QSize(4, 5), 6);
Q_UNUSED(pSI);
}
@@ -203,9 +228,9 @@ void tst_QPair::taskQTBUG_48780_pairContainingCArray()
Q_UNUSED(pair);
}
-void tst_QPair::testDeducationRules()
+void tst_QPair::testDeductionRules()
{
-#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201606
+#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201907L
QPair p1{1, 2};
static_assert(std::is_same<decltype(p1)::first_type, decltype(1)>::value);
static_assert(std::is_same<decltype(p1)::second_type, decltype(2)>::value);
@@ -224,7 +249,7 @@ void tst_QPair::testDeducationRules()
QCOMPARE(p3.first, "string");
QCOMPARE(p3.second, 2);
#else
- QSKIP("Unsupported");
+ QSKIP("Unsupported (requires C++20's CTAD for aliases)");
#endif
}
diff --git a/tests/auto/corelib/tools/qpoint/CMakeLists.txt b/tests/auto/corelib/tools/qpoint/CMakeLists.txt
new file mode 100644
index 0000000000..f1402d8815
--- /dev/null
+++ b/tests/auto/corelib/tools/qpoint/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qpoint Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qpoint LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qpoint
+ SOURCES
+ tst_qpoint.cpp
+)
diff --git a/tests/auto/corelib/tools/qpoint/qpoint.pro b/tests/auto/corelib/tools/qpoint/qpoint.pro
deleted file mode 100644
index 8321d08fe0..0000000000
--- a/tests/auto/corelib/tools/qpoint/qpoint.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qpoint
-QT = core testlib
-SOURCES = tst_qpoint.cpp
diff --git a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
index f25492d2db..7fea787131 100644
--- a/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
+++ b/tests/auto/corelib/tools/qpoint/tst_qpoint.cpp
@@ -1,35 +1,35 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QPoint>
+#ifdef QVARIANT_H
+# error "This test requires qpoint.h to not include qvariant.h"
+#endif
+
+// don't assume <type_traits>
+template <typename T, typename U>
+constexpr inline bool my_is_same_v = false;
+template <typename T>
+constexpr inline bool my_is_same_v<T, T> = true;
+
+#define CHECK(cvref) \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QPoint cvref >())), int cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QPoint cvref >())), int cvref >)
+
+CHECK(&);
+CHECK(const &);
+CHECK(&&);
+CHECK(const &&);
+
+#undef CHECK
+
+#include <QTest>
+#include <QBuffer>
#include <qpoint.h>
+#include <array>
+
class tst_QPoint : public QObject
{
Q_OBJECT
@@ -44,6 +44,9 @@ private slots:
void transposed();
+ void toPointF_data();
+ void toPointF();
+
void rx();
void ry();
@@ -75,6 +78,8 @@ private slots:
void stream_data();
void stream();
#endif
+
+ void structuredBinding();
};
void tst_QPoint::isNull()
@@ -128,6 +133,30 @@ void tst_QPoint::getSet()
QCOMPARE(point.y(), i);
}
+void tst_QPoint::toPointF_data()
+{
+ QTest::addColumn<QPoint>("input");
+ QTest::addColumn<QPointF>("result");
+
+ auto row = [](int x, int y) {
+ QTest::addRow("(%d, %d)", x, y) << QPoint(x, y) << QPointF(x, y);
+ };
+ constexpr std::array samples = {-1, 0, 1};
+ for (int x : samples) {
+ for (int y : samples) {
+ row(x, y);
+ }
+ }
+}
+
+void tst_QPoint::toPointF()
+{
+ QFETCH(const QPoint, input);
+ QFETCH(const QPointF, result);
+
+ QCOMPARE(input.toPointF(), result);
+}
+
void tst_QPoint::transposed()
{
QCOMPARE(QPoint(1, 2).transposed(), QPoint(2, 1));
@@ -346,6 +375,9 @@ void tst_QPoint::operator_eq()
QCOMPARE(equal, expectEqual);
bool notEqual = point1 != point2;
QCOMPARE(notEqual, !expectEqual);
+
+ if (equal)
+ QCOMPARE(qHash(point1), qHash(point2));
}
#ifndef QT_NO_DATASTREAM
@@ -378,5 +410,62 @@ void tst_QPoint::stream()
}
#endif
+void tst_QPoint::structuredBinding()
+{
+ {
+ QPoint p(1, 2);
+ auto [x, y] = p;
+ QCOMPARE(x, 1);
+ QCOMPARE(y, 2);
+
+ p.setX(42);
+ QCOMPARE(x, 1);
+ QCOMPARE(y, 2);
+
+ p.setY(-123);
+ QCOMPARE(x, 1);
+ QCOMPARE(y, 2);
+ }
+ {
+ QPoint p(1, 2);
+
+ auto &[x, y] = p;
+ QCOMPARE(x, 1);
+ QCOMPARE(y, 2);
+
+ x = 42;
+ QCOMPARE(x, 42);
+ QCOMPARE(p.x(), 42);
+ QCOMPARE(p.rx(), 42);
+ QCOMPARE(y, 2);
+ QCOMPARE(p.y(), 2);
+ QCOMPARE(p.ry(), 2);
+
+ y = -123;
+ QCOMPARE(x, 42);
+ QCOMPARE(p.x(), 42);
+ QCOMPARE(p.rx(), 42);
+ QCOMPARE(y, -123);
+ QCOMPARE(p.y(), -123);
+ QCOMPARE(p.ry(), -123);
+
+ p.setX(0);
+ QCOMPARE(x, 0);
+ QCOMPARE(p.x(), 0);
+ QCOMPARE(p.rx(), 0);
+ QCOMPARE(y, -123);
+ QCOMPARE(p.y(), -123);
+ QCOMPARE(p.ry(), -123);
+
+ p.ry() = 10;
+ QCOMPARE(x, 0);
+ QCOMPARE(p.x(), 0);
+ QCOMPARE(p.rx(), 0);
+ QCOMPARE(y, 10);
+ QCOMPARE(p.y(), 10);
+ QCOMPARE(p.ry(), 10);
+ }
+}
+
QTEST_MAIN(tst_QPoint)
#include "tst_qpoint.moc"
diff --git a/tests/auto/corelib/tools/qpointf/CMakeLists.txt b/tests/auto/corelib/tools/qpointf/CMakeLists.txt
new file mode 100644
index 0000000000..16e5a9036a
--- /dev/null
+++ b/tests/auto/corelib/tools/qpointf/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qpointf Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qpointf LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qpointf
+ SOURCES
+ tst_qpointf.cpp
+)
diff --git a/tests/auto/corelib/tools/qpointf/qpointf.pro b/tests/auto/corelib/tools/qpointf/qpointf.pro
deleted file mode 100644
index 5715b95d96..0000000000
--- a/tests/auto/corelib/tools/qpointf/qpointf.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qpointf
-QT = core testlib
-SOURCES = tst_qpointf.cpp
diff --git a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
index e78a8e3082..392c22c70a 100644
--- a/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
+++ b/tests/auto/corelib/tools/qpointf/tst_qpointf.cpp
@@ -1,32 +1,30 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QPointF>
+#ifdef QVARIANT_H
+# error "This test requires qpoint.h to not include qvariant.h"
+#endif
+
+// don't assume <type_traits>
+template <typename T, typename U>
+constexpr inline bool my_is_same_v = false;
+template <typename T>
+constexpr inline bool my_is_same_v<T, T> = true;
+
+#define CHECK(cvref) \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QPointF cvref >())), qreal cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QPointF cvref >())), qreal cvref >)
+
+CHECK(&);
+CHECK(const &);
+CHECK(&&);
+CHECK(const &&);
+
+#undef CHECK
+
+#include <QTest>
+#include <QBuffer>
#include <qpoint.h>
@@ -86,6 +84,8 @@ private slots:
void stream();
#endif
+ void structuredBinding();
+
private:
const qreal QREAL_MIN;
const qreal QREAL_MAX;
@@ -381,7 +381,7 @@ void tst_QPointF::toPoint_data()
QTest::newRow("(0.0, 0.0) ==> (0, 0)") << QPointF(0, 0) << QPoint(0, 0);
QTest::newRow("(0.5, 0.5) ==> (1, 1)") << QPointF(0.5, 0.5) << QPoint(1, 1);
- QTest::newRow("(-0.5, -0.5) ==> (0, 0)") << QPointF(-0.5, -0.5) << QPoint(0, 0);
+ QTest::newRow("(-0.5, -0.5) ==> (-1, -1)") << QPointF(-0.5, -0.5) << QPoint(-1, -1);
}
void tst_QPointF::toPoint()
@@ -462,5 +462,63 @@ void tst_QPointF::compare()
QVERIFY(QPointF(1.9543e-14, -32.0) == QPointF(0.0, -32.0));
}
+
+void tst_QPointF::structuredBinding()
+{
+ {
+ QPointF p(1.5, 2.25);
+ auto [x, y] = p;
+ QCOMPARE(x, 1.5);
+ QCOMPARE(y, 2.25);
+
+ p.setX(42);
+ QCOMPARE(x, 1.5);
+ QCOMPARE(y, 2.25);
+
+ p.setY(-123);
+ QCOMPARE(x, 1.5);
+ QCOMPARE(y, 2.25);
+ }
+ {
+ QPointF p(1.5, 2.25);
+
+ auto &[x, y] = p;
+ QCOMPARE(x, 1.5);
+ QCOMPARE(y, 2.25);
+
+ x = 42.0;
+ QCOMPARE(x, 42.0);
+ QCOMPARE(p.x(), 42.0);
+ QCOMPARE(p.rx(), 42.0);
+ QCOMPARE(y, 2.25);
+ QCOMPARE(p.y(), 2.25);
+ QCOMPARE(p.ry(), 2.25);
+
+ y = -123.5;
+ QCOMPARE(x, 42.0);
+ QCOMPARE(p.x(), 42.0);
+ QCOMPARE(p.rx(), 42.0);
+ QCOMPARE(y, -123.5);
+ QCOMPARE(p.y(), -123.5);
+ QCOMPARE(p.ry(), -123.5);
+
+ p.setX(0.0);
+ QCOMPARE(x, 0.0);
+ QCOMPARE(p.x(), 0.0);
+ QCOMPARE(p.rx(), 0.0);
+ QCOMPARE(y, -123.5);
+ QCOMPARE(p.y(), -123.5);
+ QCOMPARE(p.ry(), -123.5);
+
+ p.ry() = 10.5;
+ QCOMPARE(x, 0.0);
+ QCOMPARE(p.x(), 0.0);
+ QCOMPARE(p.rx(), 0.0);
+ QCOMPARE(y, 10.5);
+ QCOMPARE(p.y(), 10.5);
+ QCOMPARE(p.ry(), 10.5);
+ }
+}
+
QTEST_MAIN(tst_QPointF)
#include "tst_qpointf.moc"
diff --git a/tests/auto/corelib/tools/qqueue/CMakeLists.txt b/tests/auto/corelib/tools/qqueue/CMakeLists.txt
new file mode 100644
index 0000000000..bf229eee6a
--- /dev/null
+++ b/tests/auto/corelib/tools/qqueue/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qqueue Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qqueue LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qqueue
+ SOURCES
+ tst_qqueue.cpp
+)
diff --git a/tests/auto/corelib/tools/qqueue/qqueue.pro b/tests/auto/corelib/tools/qqueue/qqueue.pro
deleted file mode 100644
index 55ceb65fbd..0000000000
--- a/tests/auto/corelib/tools/qqueue/qqueue.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qqueue
-QT = core testlib
-SOURCES = tst_qqueue.cpp
diff --git a/tests/auto/corelib/tools/qqueue/tst_qqueue.cpp b/tests/auto/corelib/tools/qqueue/tst_qqueue.cpp
index 6c391bd764..44d4c34768 100644
--- a/tests/auto/corelib/tools/qqueue/tst_qqueue.cpp
+++ b/tests/auto/corelib/tools/qqueue/tst_qqueue.cpp
@@ -1,33 +1,8 @@
-/****************************************************************************
-**
-** 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/QtTest>
+#include <QTest>
#include <qqueue.h>
class tst_QQueue : public QObject
diff --git a/tests/auto/corelib/tools/qrect/CMakeLists.txt b/tests/auto/corelib/tools/qrect/CMakeLists.txt
new file mode 100644
index 0000000000..a02e1c33a5
--- /dev/null
+++ b/tests/auto/corelib/tools/qrect/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qrect Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qrect LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qrect
+ SOURCES
+ tst_qrect.cpp
+)
diff --git a/tests/auto/corelib/tools/qrect/qrect.pro b/tests/auto/corelib/tools/qrect/qrect.pro
deleted file mode 100644
index 8ec31db215..0000000000
--- a/tests/auto/corelib/tools/qrect/qrect.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qrect
-QT = core testlib
-SOURCES = tst_qrect.cpp
diff --git a/tests/auto/corelib/tools/qrect/tst_qrect.cpp b/tests/auto/corelib/tools/qrect/tst_qrect.cpp
index 1c2221ec29..0f3dd1a0ef 100644
--- a/tests/auto/corelib/tools/qrect/tst_qrect.cpp
+++ b/tests/auto/corelib/tools/qrect/tst_qrect.cpp
@@ -1,37 +1,13 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <qrect.h>
#include <qmargins.h>
#include <limits.h>
#include <qdebug.h>
+#include <array>
class tst_QRect : public QObject
{
@@ -124,6 +100,9 @@ private slots:
void margins();
void marginsf();
+ void toRectF_data();
+ void toRectF();
+
void translate_data();
void translate();
@@ -164,14 +143,17 @@ private slots:
void intersectsRectF();
void containsRect_data();
void containsRect();
+ void containsRectNormalized();
void containsRectF_data();
void containsRectF();
void containsPoint_data();
void containsPoint();
+ void containsPointNormalized();
void containsPointF_data();
void containsPointF();
void smallRects() const;
void toRect();
+ void span();
};
// Used to work around some floating point precision problems.
@@ -372,17 +354,20 @@ void tst_QRect::normalized_data()
QTest::newRow( "LargestCoordQRect" ) << getQRectCase( LargestCoordQRect )
<< getQRectCase( LargestCoordQRect ); // overflow
QTest::newRow( "RandomQRect" ) << getQRectCase( RandomQRect ) << QRect( 100, 200, 11, 16 );
- QTest::newRow( "NegativeSizeQRect" ) << getQRectCase( NegativeSizeQRect ) << QRect(QPoint(-10,-10),QPoint(1,1));
+ QTest::newRow( "NegativeSizeQRect" ) << getQRectCase( NegativeSizeQRect ) << QRect(-9, -9, 10, 10);
QTest::newRow( "NegativePointQRect" ) << getQRectCase( NegativePointQRect ) << QRect( -10, -10, 5, 5 );
QTest::newRow( "NullQRect" ) << getQRectCase( NullQRect ) << getQRectCase( NullQRect );
QTest::newRow( "EmptyQRect" ) << getQRectCase( EmptyQRect ) << getQRectCase( EmptyQRect );
QTest::newRow( "ZeroWidth" ) << QRect(100, 200, 100, 0) << QRect(100, 200, 100, 0);
+ QTest::newRow( "ZeroHeight" ) << QRect(100, 200, 0, 100) << QRect(100, 200, 0, 100);
// Since "NegativeSizeQRect passes, I expect both of these to pass too.
// This passes, since height() returns -1 before normalization
- QTest::newRow( "NegativeHeight") << QRect(QPoint(100,201), QPoint(199,199)) << QRect(QPoint(100,199), QPoint(199,201));
+ QTest::newRow( "NegativeWidth") << QRect(QPoint(200,100), QSize(-1,100)) << QRect(QPoint(199,100), QSize(1,100));
+ QTest::newRow( "NegativeHeight") << QRect(QPoint(100,200), QSize(100,-1)) << QRect(QPoint(100,199), QSize(100,1));
+ QTest::newRow( "NegativeWidth2") << QRect(QPoint(200,100), QPoint(198,199)) << QRect(QPoint(199,100), QPoint(199,199));
// This, on the other hand height() returns 0 before normalization.
- QTest::newRow( "ZeroHeight1" ) << QRect(QPoint(100,200), QPoint(199,199)) << QRect(QPoint(100,199), QPoint(199,200));
- QTest::newRow( "ZeroHeight2" ) << QRect(QPoint(263,113), QPoint(136,112)) << QRect(QPoint(136,113), QPoint(263,112));
+ QTest::newRow( "ZeroHeight1" ) << QRect(QPoint(100,200), QPoint(199,199)) << QRect(QPoint(100,200), QPoint(199,199));
+ QTest::newRow( "ZeroHeight2" ) << QRect(QPoint(263,113), QPoint(136,112)) << QRect(QPoint(137,113), QPoint(262,112));
}
void tst_QRect::normalized()
@@ -390,7 +375,6 @@ void tst_QRect::normalized()
QFETCH(QRect, r);
QFETCH(QRect, nr);
- QEXPECT_FAIL("ZeroHeight1", "due to broken QRect definition (not possible to change, see QTBUG-22934)", Continue);
QCOMPARE(r.normalized(), nr);
}
@@ -478,6 +462,9 @@ void tst_QRect::right()
if (isLarge(r.width()))
return;
+ // width overflow
+ if (r.left() < r.right() && r.width() < 0)
+ return;
QCOMPARE(QRectF(r).right(), qreal(right+1));
}
@@ -510,6 +497,9 @@ void tst_QRect::bottom()
if (isLarge(r.height()))
return;
+ // height overflow
+ if (r.top() < r.bottom() && r.height() < 0)
+ return;
QCOMPARE(QRectF(r).bottom(), qreal(bottom + 1));
}
@@ -2515,16 +2505,11 @@ void tst_QRect::newMoveLeft_data()
{
// QTest::newRow( "LargestCoordQRect_MinimumInt" ) -- Not tested as it would cause an overflow
- QTest::newRow( "LargestCoordQRect_MiddleNegativeInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MiddleNegativeInt )
- << QRect( QPoint( INT_MIN/2, INT_MIN ), QPoint(INT_MIN/2-1, INT_MAX ) );
- QTest::newRow( "LargestCoordQRect_ZeroInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( ZeroInt )
- << QRect( QPoint( 0, INT_MIN ), QPoint(-1, INT_MAX ) );
- QTest::newRow( "LargestCoordQRect_MiddlePositiveInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MiddlePositiveInt )
- << QRect( QPoint( INT_MAX/2, INT_MIN ), QPoint(INT_MAX/2-1, INT_MAX ) );
- QTest::newRow( "LargestCoordQRect_MaximumInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MaximumInt )
- << QRect( QPoint( INT_MAX, INT_MIN ), QPoint(INT_MAX-1, INT_MAX ) );
- QTest::newRow( "LargestCoordQRect_RandomInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( RandomInt )
- << QRect( QPoint( 4953, INT_MIN ), QPoint(4952, INT_MAX ) );
+ // QTest::newRow( "LargestCoordQRect_MiddleNegativeInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_ZeroInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_MiddlePositiveInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_MaximumInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_RandomInt" ) -- Not tested as it would cause an overflow
}
{
@@ -2684,16 +2669,11 @@ void tst_QRect::newMoveTop_data()
{
// QTest::newRow( "LargestCoordQRect_MinimumInt" ) -- Not tested as it would cause an overflow
- QTest::newRow( "LargestCoordQRect_MiddleNegativeInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MiddleNegativeInt )
- << QRect( QPoint(INT_MIN,INT_MIN/2), QPoint(INT_MAX,INT_MIN/2-1) );
- QTest::newRow( "LargestCoordQRect_ZeroInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( ZeroInt )
- << QRect( QPoint(INT_MIN,0), QPoint(INT_MAX,-1) );
- QTest::newRow( "LargestCoordQRect_MiddlePositiveInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MiddlePositiveInt )
- << QRect( QPoint(INT_MIN,INT_MAX/2), QPoint(INT_MAX,INT_MAX/2-1) );
- QTest::newRow( "LargestCoordQRect_MaximumInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( MaximumInt )
- << QRect( QPoint(INT_MIN,INT_MAX), QPoint(INT_MAX,INT_MAX-1) );
- QTest::newRow( "LargestCoordQRect_RandomInt" ) << getQRectCase( LargestCoordQRect ) << getIntCase( RandomInt )
- << QRect( QPoint(INT_MIN,4953), QPoint(INT_MAX,4952) );
+ // QTest::newRow( "LargestCoordQRect_MiddleNegativeInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_ZeroInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_MiddlePositiveInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_MaximumInt" ) -- Not tested as it would cause an overflow
+ // QTest::newRow( "LargestCoordQRect_RandomInt" ) -- Not tested as it would cause an overflow
}
{
@@ -3525,6 +3505,39 @@ void tst_QRect::marginsf()
QCOMPARE(a, rectangle.marginsRemoved(margins));
}
+void tst_QRect::toRectF_data()
+{
+ QTest::addColumn<QRect>("input");
+ QTest::addColumn<QRectF>("result");
+
+ auto row = [](int x1, int y1, int w, int h) {
+ // QRectF -> QRect conversion tries to maintain size(), not bottomRight(),
+ // so compare in (topLeft(), size()) space
+ QTest::addRow("((%d, %d) (%dx%d))", x1, y1, w, h)
+ << QRect({x1, y1}, QSize{w, h}) << QRectF(QPointF(x1, y1), QSizeF(w, h));
+ };
+ constexpr std::array samples = {-1, 0, 1};
+ for (int x1 : samples) {
+ for (int y1 : samples) {
+ for (int w : samples) {
+ for (int h : samples) {
+ row(x1, y1, w, h);
+ }
+ }
+ }
+ }
+}
+
+void tst_QRect::toRectF()
+{
+ QFETCH(const QRect, input);
+ QFETCH(const QRectF, result);
+
+ QCOMPARE(result.toRect(), input); // consistency check
+ QCOMPARE(input.toRectF(), result);
+}
+
+
void tst_QRect::translate_data()
{
QTest::addColumn<QRect>("r");
@@ -3931,15 +3944,15 @@ void tst_QRect::intersectedRect_data()
QTest::newRow("test 03") << QRect(0, 0, 10, 10) << QRect( 2, 2, 10, 10) << QRect(2, 2, 8, 8);
QTest::newRow("test 04") << QRect(0, 0, 10, 10) << QRect(20, 20, 10, 10) << QRect();
- QTest::newRow("test 05") << QRect(9, 9, -8, -8) << QRect( 2, 2, 6, 6) << QRect(2, 2, 6, 6);
- QTest::newRow("test 06") << QRect(9, 9, -8, -8) << QRect( 0, 0, 10, 10) << QRect(0, 0, 10, 10);
- QTest::newRow("test 07") << QRect(9, 9, -8, -8) << QRect( 2, 2, 10, 10) << QRect(2, 2, 8, 8);
- QTest::newRow("test 08") << QRect(9, 9, -8, -8) << QRect(20, 20, 10, 10) << QRect();
+ QTest::newRow("test 05") << QRect(10, 10, -10, -10) << QRect( 2, 2, 6, 6) << QRect(2, 2, 6, 6);
+ QTest::newRow("test 06") << QRect(10, 10, -10, -10) << QRect( 0, 0, 10, 10) << QRect(0, 0, 10, 10);
+ QTest::newRow("test 07") << QRect(10, 10, -10, -10) << QRect( 2, 2, 10, 10) << QRect(2, 2, 8, 8);
+ QTest::newRow("test 08") << QRect(10, 10, -10, -10) << QRect(20, 20, 10, 10) << QRect();
- QTest::newRow("test 09") << QRect(0, 0, 10, 10) << QRect( 7, 7, -4, -4) << QRect(2, 2, 6, 6);
- QTest::newRow("test 10") << QRect(0, 0, 10, 10) << QRect( 9, 9, -8, -8) << QRect(0, 0, 10, 10);
- QTest::newRow("test 11") << QRect(0, 0, 10, 10) << QRect(11, 11, -8, -8) << QRect(2, 2, 8, 8);
- QTest::newRow("test 12") << QRect(0, 0, 10, 10) << QRect(29, 29, -8, -8) << QRect();
+ QTest::newRow("test 09") << QRect(0, 0, 10, 10) << QRect( 6, 6, -4, -4) << QRect(2, 2, 4, 4);
+ QTest::newRow("test 10") << QRect(0, 0, 10, 10) << QRect(10, 10, -10, -10) << QRect(0, 0, 10, 10);
+ QTest::newRow("test 11") << QRect(0, 0, 10, 10) << QRect(12, 12, -10, -10) << QRect(2, 2, 8, 8);
+ QTest::newRow("test 12") << QRect(0, 0, 10, 10) << QRect(30, 30, -10, -10) << QRect();
QTest::newRow("test 13") << QRect(0, 0, 10, 10) << QRect() << QRect();
QTest::newRow("test 14") << QRect() << QRect(0, 0, 10, 10) << QRect();
@@ -4016,15 +4029,15 @@ void tst_QRect::unitedRect_data()
QTest::newRow("test 03") << QRect(0, 0, 10, 10) << QRect( 2, 2, 10, 10) << QRect(0, 0, 12, 12);
QTest::newRow("test 04") << QRect(0, 0, 10, 10) << QRect(20, 20, 10, 10) << QRect(0, 0, 30, 30);
- QTest::newRow("test 05") << QRect(9, 9, -8, -8) << QRect( 2, 2, 6, 6) << QRect(0, 0, 10, 10);
- QTest::newRow("test 06") << QRect(9, 9, -8, -8) << QRect( 0, 0, 10, 10) << QRect(0, 0, 10, 10);
- QTest::newRow("test 07") << QRect(9, 9, -8, -8) << QRect( 2, 2, 10, 10) << QRect(0, 0, 12, 12);
- QTest::newRow("test 08") << QRect(9, 9, -8, -8) << QRect(20, 20, 10, 10) << QRect(0, 0, 30, 30);
+ QTest::newRow("test 05") << QRect(10, 10, -10, -10) << QRect( 2, 2, 6, 6) << QRect(0, 0, 10, 10);
+ QTest::newRow("test 06") << QRect(10, 10, -10, -10) << QRect( 0, 0, 10, 10) << QRect(0, 0, 10, 10);
+ QTest::newRow("test 07") << QRect(10, 10, -10, -10) << QRect( 2, 2, 10, 10) << QRect(0, 0, 12, 12);
+ QTest::newRow("test 08") << QRect(10, 10, -10, -10) << QRect(20, 20, 10, 10) << QRect(0, 0, 30, 30);
QTest::newRow("test 09") << QRect(0, 0, 10, 10) << QRect( 7, 7, -4, -4) << QRect(0, 0, 10, 10);
QTest::newRow("test 10") << QRect(0, 0, 10, 10) << QRect( 9, 9, -8, -8) << QRect(0, 0, 10, 10);
- QTest::newRow("test 11") << QRect(0, 0, 10, 10) << QRect(11, 11, -8, -8) << QRect(0, 0, 12, 12);
- QTest::newRow("test 12") << QRect(0, 0, 10, 10) << QRect(29, 29, -8, -8) << QRect(0, 0, 30, 30);
+ QTest::newRow("test 11") << QRect(0, 0, 10, 10) << QRect(12, 12, -8, -8) << QRect(0, 0, 12, 12);
+ QTest::newRow("test 12") << QRect(0, 0, 10, 10) << QRect(30, 30, -8, -8) << QRect(0, 0, 30, 30);
QTest::newRow("test 13") << QRect() << QRect(10, 10, 10, 10) << QRect(10, 10, 10, 10);
QTest::newRow("test 14") << QRect(10, 10, 10, 10) << QRect() << QRect(10, 10, 10, 10);
@@ -4166,10 +4179,10 @@ void tst_QRect::containsRect_data()
QTest::newRow("test 03") << QRect(0, 0, 10, 10) << QRect( 2, 2, 10, 10) << false;
QTest::newRow("test 04") << QRect(0, 0, 10, 10) << QRect(20, 20, 10, 10) << false;
- QTest::newRow("test 05") << QRect(9, 9, -8, -8) << QRect( 2, 2, 6, 6) << true;
- QTest::newRow("test 06") << QRect(9, 9, -8, -8) << QRect( 0, 0, 10, 10) << true;
- QTest::newRow("test 07") << QRect(9, 9, -8, -8) << QRect( 2, 2, 10, 10) << false;
- QTest::newRow("test 08") << QRect(9, 9, -8, -8) << QRect(20, 20, 10, 10) << false;
+ QTest::newRow("test 05") << QRect(9, 9, -9, -9) << QRect( 2, 2, 6, 6) << true;
+ QTest::newRow("test 06") << QRect(9, 9, -9, -9) << QRect( 0, 0, 9, 9) << true;
+ QTest::newRow("test 07") << QRect(9, 9, -9, -9) << QRect( 2, 2, 9, 9) << false;
+ QTest::newRow("test 08") << QRect(9, 9, -9, -9) << QRect(20, 20, 10, 10) << false;
QTest::newRow("test 09") << QRect(0, 0, 10, 10) << QRect( 7, 7, -4, -4) << true;
QTest::newRow("test 10") << QRect(0, 0, 10, 10) << QRect( 9, 9, -8, -8) << true;
@@ -4190,6 +4203,18 @@ void tst_QRect::containsRect()
QVERIFY(rect1.contains(rect2) == contains);
}
+void tst_QRect::containsRectNormalized()
+{
+ QRect rect(QPoint(10, 10), QPoint(0,0));
+ QRect normalized = rect.normalized();
+ for (int i = -2 ; i < 12; ++i) {
+ for (int j = -2 ; j < 12; ++j) {
+ for (int k = -2 ; k <= 2; ++k)
+ QCOMPARE(rect.contains(QRect(i,j,k,k)), normalized.contains(QRect(i,j,k,k)));
+ }
+ }
+}
+
void tst_QRect::containsRectF_data()
{
QTest::addColumn<QRectF>("rect1");
@@ -4245,18 +4270,18 @@ void tst_QRect::containsPoint_data()
QTest::newRow("test 11") << QRect(0, 0, 10, 10) << QPoint( 1, 8) << true << true;
QTest::newRow("test 12") << QRect(0, 0, 10, 10) << QPoint( 8, 8) << true << true;
- QTest::newRow("test 13") << QRect(9, 9, -8, -8) << QPoint( 0, 0) << true << false;
- QTest::newRow("test 14") << QRect(9, 9, -8, -8) << QPoint( 0, 10) << false << false;
- QTest::newRow("test 15") << QRect(9, 9, -8, -8) << QPoint(10, 0) << false << false;
- QTest::newRow("test 16") << QRect(9, 9, -8, -8) << QPoint(10, 10) << false << false;
- QTest::newRow("test 17") << QRect(9, 9, -8, -8) << QPoint( 0, 9) << true << false;
- QTest::newRow("test 18") << QRect(9, 9, -8, -8) << QPoint( 9, 0) << true << false;
- QTest::newRow("test 19") << QRect(9, 9, -8, -8) << QPoint( 9, 9) << true << false;
- QTest::newRow("test 20") << QRect(9, 9, -8, -8) << QPoint( 1, 0) << true << false;
- QTest::newRow("test 21") << QRect(9, 9, -8, -8) << QPoint( 9, 1) << true << false;
- QTest::newRow("test 22") << QRect(9, 9, -8, -8) << QPoint( 1, 1) << true << true;
- QTest::newRow("test 23") << QRect(9, 9, -8, -8) << QPoint( 1, 8) << true << true;
- QTest::newRow("test 24") << QRect(9, 9, -8, -8) << QPoint( 8, 8) << true << true;
+ QTest::newRow("test 13") << QRect(9, 9, -9, -9) << QPoint( 0, 0) << true << false;
+ QTest::newRow("test 14") << QRect(9, 9, -9, -9) << QPoint( 0, 9) << false << false;
+ QTest::newRow("test 15") << QRect(9, 9, -9, -9) << QPoint( 9, 0) << false << false;
+ QTest::newRow("test 16") << QRect(9, 9, -9, -9) << QPoint( 9, 9) << false << false;
+ QTest::newRow("test 17") << QRect(9, 9, -9, -9) << QPoint( 0, 8) << true << false;
+ QTest::newRow("test 18") << QRect(9, 9, -9, -9) << QPoint( 8, 0) << true << false;
+ QTest::newRow("test 19") << QRect(9, 9, -9, -9) << QPoint( 8, 8) << true << false;
+ QTest::newRow("test 20") << QRect(9, 9, -9, -9) << QPoint( 1, 0) << true << false;
+ QTest::newRow("test 21") << QRect(9, 9, -9, -9) << QPoint( 8, 1) << true << false;
+ QTest::newRow("test 22") << QRect(9, 9, -9, -9) << QPoint( 1, 1) << true << true;
+ QTest::newRow("test 23") << QRect(9, 9, -9, -9) << QPoint( 1, 7) << true << true;
+ QTest::newRow("test 24") << QRect(9, 9, -9, -9) << QPoint( 7, 7) << true << true;
QTest::newRow("test 25") << QRect(-1, 1, 10, 10) << QPoint() << false << false;
QTest::newRow("test 26") << QRect() << QPoint(1, 1) << false << false;
@@ -4274,14 +4299,22 @@ void tst_QRect::containsPoint()
QVERIFY(rect.contains(point, true) == containsProper);
}
+void tst_QRect::containsPointNormalized()
+{
+ QRect rect(QPoint(10, 10), QPoint(0,0));
+ QRect normalized = rect.normalized();
+ for (int i = 0 ; i < 10; ++i) {
+ for (int j = 0 ; j < 10; ++j)
+ QCOMPARE(rect.contains(QPoint(i,j)), normalized.contains(QPoint(i,j)));
+ }
+}
+
void tst_QRect::containsPointF_data()
{
QTest::addColumn<QRectF>("rect");
QTest::addColumn<QPointF>("point");
QTest::addColumn<bool>("contains");
- QTest::newRow("test 27") << QRectF() << QPointF() << false;
-
QTest::newRow("test 01") << QRectF(0, 0, 10, 10) << QPointF( 0, 0) << true;
QTest::newRow("test 02") << QRectF(0, 0, 10, 10) << QPointF( 0, 10) << true;
QTest::newRow("test 03") << QRectF(0, 0, 10, 10) << QPointF(10, 0) << true;
@@ -4340,12 +4373,12 @@ void tst_QRect::toRect()
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);
+ QVERIFY(qAbs(rect.x() - rectf.x()) <= 0.75);
+ QVERIFY(qAbs(rect.y() - rectf.y()) <= 0.75);
+ QVERIFY(qAbs(rect.width() - rectf.width()) <= 0.75);
+ QVERIFY(qAbs(rect.height() - rectf.height()) <= 0.75);
+ QVERIFY(qAbs(rect.right() - rectf.right()) <= 0.75);
+ QVERIFY(qAbs(rect.bottom() - rectf.bottom()) <= 0.75);
const QRectF arect = rectf.toAlignedRect();
QVERIFY(qAbs(arect.x() - rectf.x()) < 1.0);
@@ -4363,5 +4396,16 @@ void tst_QRect::toRect()
}
}
+void tst_QRect::span()
+{
+ QCOMPARE(QRect::span(QPoint( 0, 1), QPoint(9, 10)), QRect(QPoint(0, 1), QPoint( 9, 10)));
+
+ QCOMPARE(QRect::span(QPoint(10, 9), QPoint(1, 0)), QRect(QPoint(1, 0), QPoint(10, 9)));
+
+ QCOMPARE(QRect::span(QPoint(10, 1), QPoint(0, 9)), QRect(QPoint(0, 1), QPoint(10, 9)));
+
+ QCOMPARE(QRect::span(QPoint( 1, 10), QPoint(9, 0)), QRect(QPoint(1, 0), QPoint( 9, 10)));
+}
+
QTEST_MAIN(tst_QRect)
#include "tst_qrect.moc"
diff --git a/tests/auto/corelib/tools/qringbuffer/CMakeLists.txt b/tests/auto/corelib/tools/qringbuffer/CMakeLists.txt
new file mode 100644
index 0000000000..cfb7c6f461
--- /dev/null
+++ b/tests/auto/corelib/tools/qringbuffer/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qringbuffer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qringbuffer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qringbuffer
+ SOURCES
+ tst_qringbuffer.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qringbuffer/qringbuffer.pro b/tests/auto/corelib/tools/qringbuffer/qringbuffer.pro
deleted file mode 100644
index c63544035a..0000000000
--- a/tests/auto/corelib/tools/qringbuffer/qringbuffer.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qringbuffer
-QT = core-private testlib
-SOURCES = tst_qringbuffer.cpp
diff --git a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
index e355a7fcfb..c7b79cfae1 100644
--- a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
+++ b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
@@ -1,35 +1,12 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QBuffer>
+#include <QVarLengthArray>
#include <private/qringbuffer_p.h>
-#include <qvector.h>
+#include <qlist.h>
class tst_QRingBuffer : public QObject
{
@@ -37,6 +14,7 @@ class tst_QRingBuffer : public QObject
private slots:
void constructing();
void usingInVector();
+ void usingInVarLengthArray();
void readPointerAtPositionWriteRead();
void readPointerAtPositionEmptyRead();
void readPointerAtPositionWithHead();
@@ -82,10 +60,20 @@ void tst_QRingBuffer::constructing()
void tst_QRingBuffer::usingInVector()
{
QRingBuffer ringBuffer;
- QVector<QRingBuffer> buffers;
+ std::vector<QRingBuffer> buffers;
+
+ ringBuffer.reserve(5);
+ buffers.push_back(std::move(ringBuffer));
+ QCOMPARE(buffers[0].size(), Q_INT64_C(5));
+}
+
+void tst_QRingBuffer::usingInVarLengthArray()
+{
+ QRingBuffer ringBuffer;
+ QVarLengthArray<QRingBuffer, 42> buffers;
ringBuffer.reserve(5);
- buffers.append(ringBuffer);
+ buffers.push_back(std::move(ringBuffer));
QCOMPARE(buffers[0].size(), Q_INT64_C(5));
}
diff --git a/tests/auto/corelib/tools/qscopedpointer/CMakeLists.txt b/tests/auto/corelib/tools/qscopedpointer/CMakeLists.txt
new file mode 100644
index 0000000000..7bfcfdebbf
--- /dev/null
+++ b/tests/auto/corelib/tools/qscopedpointer/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qscopedpointer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qscopedpointer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qscopedpointer
+ SOURCES
+ tst_qscopedpointer.cpp
+)
diff --git a/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro b/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro
deleted file mode 100644
index 5248ad5528..0000000000
--- a/tests/auto/corelib/tools/qscopedpointer/qscopedpointer.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qscopedpointer
-QT = core testlib
-SOURCES = tst_qscopedpointer.cpp
diff --git a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp
index ea94cc2999..3468c97f42 100644
--- a/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp
+++ b/tests/auto/corelib/tools/qscopedpointer/tst_qscopedpointer.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <QtCore/QScopedPointer>
/*!
@@ -61,6 +36,11 @@ private Q_SLOTS:
void comparison();
void array();
// TODO instanciate on const object
+
+ // Tests for deprecated APIs
+#if QT_DEPRECATED_SINCE(6, 1)
+ void deprecatedTake();
+#endif // QT_DEPRECATED_SINCE(6, 1)
};
void tst_QScopedPointer::defaultConstructor()
@@ -160,7 +140,7 @@ public:
class SubClass : public AbstractClass
{
public:
- virtual int member() const
+ virtual int member() const override
{
return 5;
}
@@ -252,7 +232,7 @@ void tst_QScopedPointer::negationOperatorSignature()
!p;
/* The return value should be bool. */
- static_cast<bool>(!p);
+ Q_UNUSED(static_cast<bool>(!p));
}
void tst_QScopedPointer::operatorBool()
@@ -302,7 +282,7 @@ void tst_QScopedPointer::isNullSignature()
const QScopedPointer<int> p(new int(69));
/* The signature should be const and return bool. */
- static_cast<bool>(p.isNull());
+ Q_UNUSED(static_cast<bool>(p.isNull()));
}
void tst_QScopedPointer::objectSize()
@@ -367,53 +347,63 @@ void scopedPointerComparisonTest(const A1 &a1, const A2 &a2, const B &b)
QVERIFY(a2 != b);
}
+// tst_QScopedPointer::comparison creates two QScopedPointers referring to the
+// same memory. This will lead to double-deletion error during cleanup if we
+// use a default QScopedPointer{Array}Deleter. This DummyDeleter does nothing,
+// so we can safely reference the same memory from multiple QScopedPointer
+// instances, and manage the memory manually.
+// That is fine for the comparison() test, because its goal is to check the
+// object's (in)equality, not the memory management
+struct DummyDeleter
+{
+ static inline void cleanup(RefCounted *) noexcept {}
+ void operator()(RefCounted *pointer) const noexcept
+ {
+ cleanup(pointer);
+ }
+};
+
void tst_QScopedPointer::comparison()
{
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
- RefCounted *a = new RefCounted;
- RefCounted *b = new RefCounted;
+ auto a = std::make_unique<RefCounted>();
+ auto b = std::make_unique<RefCounted>();
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
- QScopedPointer<RefCounted> pa1(a);
- QScopedPointer<RefCounted> pa2(a);
- QScopedPointer<RefCounted> pb(b);
+ QScopedPointer<RefCounted, DummyDeleter> pa1(a.get());
+ QScopedPointer<RefCounted, DummyDeleter> pa2(a.get());
+ QScopedPointer<RefCounted, DummyDeleter> pb(b.get());
scopedPointerComparisonTest(pa1, pa1, pb);
scopedPointerComparisonTest(pa2, pa2, pb);
scopedPointerComparisonTest(pa1, pa2, pb);
- pa2.take();
-
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
}
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
- RefCounted *a = new RefCounted[42];
- RefCounted *b = new RefCounted[43];
+ auto a = std::make_unique<RefCounted[]>(42);
+ auto b = std::make_unique<RefCounted[]>(43);
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
- QScopedArrayPointer<RefCounted> pa1(a);
- QScopedArrayPointer<RefCounted> pa2(a);
- QScopedArrayPointer<RefCounted> pb(b);
+ QScopedArrayPointer<RefCounted, DummyDeleter> pa1(a.get());
+ QScopedArrayPointer<RefCounted, DummyDeleter> pa2(a.get());
+ QScopedArrayPointer<RefCounted, DummyDeleter> pb(b.get());
scopedPointerComparisonTest(pa1, pa2, pb);
- pa2.take();
-
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
}
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
- // QScopedSharedPointer is an internal helper class -- it is unsupported!
-
RefCounted *a = new RefCounted;
RefCounted *b = new RefCounted;
@@ -455,6 +445,23 @@ void tst_QScopedPointer::array()
QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
}
+#if QT_DEPRECATED_SINCE(6, 1)
+void tst_QScopedPointer::deprecatedTake()
+{
+ RefCounted *a = new RefCounted;
+
+ QScopedPointer<RefCounted> pa1(a);
+ QScopedPointer<RefCounted> pa2(a);
+
+ QCOMPARE(RefCounted::instanceCount.loadRelaxed(), 1);
+
+ QT_IGNORE_DEPRECATIONS(pa2.take();)
+
+ // check that pa2 holds nullptr, but the memory was not released
+ QVERIFY(pa2.isNull());
+ QCOMPARE(RefCounted::instanceCount.loadRelaxed(), 1);
+}
+#endif // QT_DEPRECATED_SINCE(6, 1)
QTEST_MAIN(tst_QScopedPointer)
#include "tst_qscopedpointer.moc"
diff --git a/tests/auto/corelib/tools/qscopedvaluerollback/CMakeLists.txt b/tests/auto/corelib/tools/qscopedvaluerollback/CMakeLists.txt
new file mode 100644
index 0000000000..359a910a0a
--- /dev/null
+++ b/tests/auto/corelib/tools/qscopedvaluerollback/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qscopedvaluerollback Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qscopedvaluerollback LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qscopedvaluerollback
+ SOURCES
+ tst_qscopedvaluerollback.cpp
+)
diff --git a/tests/auto/corelib/tools/qscopedvaluerollback/qscopedvaluerollback.pro b/tests/auto/corelib/tools/qscopedvaluerollback/qscopedvaluerollback.pro
deleted file mode 100644
index c9c0a029d3..0000000000
--- a/tests/auto/corelib/tools/qscopedvaluerollback/qscopedvaluerollback.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qscopedvaluerollback
-QT = core testlib
-SOURCES = tst_qscopedvaluerollback.cpp
diff --git a/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp b/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp
index 9b607db608..3b493b4e75 100644
--- a/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp
+++ b/tests/auto/corelib/tools/qscopedvaluerollback/tst_qscopedvaluerollback.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** 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/QtTest>
+#include <QTest>
#include <QtCore/QScopedValueRollback>
/*!
diff --git a/tests/auto/corelib/tools/qscopeguard/CMakeLists.txt b/tests/auto/corelib/tools/qscopeguard/CMakeLists.txt
new file mode 100644
index 0000000000..6f6d664554
--- /dev/null
+++ b/tests/auto/corelib/tools/qscopeguard/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qscopeguard Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qscopeguard LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qscopeguard
+ SOURCES
+ tst_qscopeguard.cpp
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/qscopeguard/qscopeguard.pro b/tests/auto/corelib/tools/qscopeguard/qscopeguard.pro
deleted file mode 100644
index 070d4b077c..0000000000
--- a/tests/auto/corelib/tools/qscopeguard/qscopeguard.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qscopeguard
-QT = core testlib
-SOURCES = tst_qscopeguard.cpp
diff --git a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
index 01181ce20e..b7c2b952e2 100644
--- a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
+++ b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
@@ -1,53 +1,144 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@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>
+// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <QtCore/QScopeGuard>
+#include <optional>
+
/*!
- \class tst_QScopedGuard
+ \class tst_QScopeGuard
\internal
\since 5.11
- \brief Tests class QScopedCleanup and function qScopeGuard
+ \brief Tests class QScopeGuard and function qScopeGuard
*/
-class tst_QScopedGuard : public QObject
+class tst_QScopeGuard : public QObject
{
Q_OBJECT
private Q_SLOTS:
+ void construction();
+ void constructionFromLvalue();
+ void constructionFromRvalue();
+ void optionalGuard();
void leavingScope();
void exceptions();
};
+void func()
+{
+}
+
+int intFunc()
+{
+ return 0;
+}
+
+[[nodiscard]] int noDiscardFunc()
+{
+ return 0;
+}
+
+struct Callable
+{
+ Callable() { }
+ Callable(const Callable &other)
+ {
+ Q_UNUSED(other);
+ ++copied;
+ }
+ Callable(Callable &&other)
+ {
+ Q_UNUSED(other);
+ ++moved;
+ }
+ void operator()() { }
+
+ static int copied;
+ static int moved;
+ static void resetCounts()
+ {
+ copied = 0;
+ moved = 0;
+ }
+};
+
+int Callable::copied = 0;
+int Callable::moved = 0;
+
static int s_globalState = 0;
-void tst_QScopedGuard::leavingScope()
+void tst_QScopeGuard::construction()
+{
+ QScopeGuard fromLambda([] { });
+ QScopeGuard fromFunction(func);
+ QScopeGuard fromFunctionPointer(&func);
+ QScopeGuard fromNonVoidFunction(intFunc);
+ QScopeGuard fromNoDiscardFunction(noDiscardFunc);
+#ifndef __apple_build_version__
+ QScopeGuard fromStdFunction{std::function<void()>(func)};
+ std::function<void()> stdFunction(func);
+ QScopeGuard fromNamedStdFunction(stdFunction);
+#endif
+}
+
+void tst_QScopeGuard::constructionFromLvalue()
+{
+ Callable::resetCounts();
+ {
+ Callable callable;
+ QScopeGuard guard(callable);
+ }
+ QCOMPARE(Callable::copied, 1);
+ QCOMPARE(Callable::moved, 0);
+ Callable::resetCounts();
+ {
+ Callable callable;
+ auto guard = qScopeGuard(callable);
+ }
+ QCOMPARE(Callable::copied, 1);
+ QCOMPARE(Callable::moved, 0);
+}
+
+void tst_QScopeGuard::constructionFromRvalue()
+{
+ Callable::resetCounts();
+ {
+ Callable callable;
+ QScopeGuard guard(std::move(callable));
+ }
+ QCOMPARE(Callable::copied, 0);
+ QCOMPARE(Callable::moved, 1);
+ Callable::resetCounts();
+ {
+ Callable callable;
+ auto guard = qScopeGuard(std::move(callable));
+ }
+ QCOMPARE(Callable::copied, 0);
+ QCOMPARE(Callable::moved, 1);
+}
+
+void tst_QScopeGuard::optionalGuard()
+{
+ int i = 0;
+ auto lambda = [&] { ++i; };
+ std::optional sg = false ? std::optional{qScopeGuard(lambda)} : std::nullopt;
+ QVERIFY(!sg);
+ QCOMPARE(i, 0);
+ sg.emplace(qScopeGuard(lambda));
+ QVERIFY(sg);
+ sg->dismiss();
+ sg.reset();
+ QCOMPARE(i, 0);
+ sg.emplace(qScopeGuard(lambda));
+ QCOMPARE(i, 0);
+ sg.reset();
+ QCOMPARE(i, 1);
+}
+
+void tst_QScopeGuard::leavingScope()
{
auto cleanup = qScopeGuard([] { s_globalState++; QCOMPARE(s_globalState, 3); });
QCOMPARE(s_globalState, 0);
@@ -61,7 +152,7 @@ void tst_QScopedGuard::leavingScope()
s_globalState++;
}
-void tst_QScopedGuard::exceptions()
+void tst_QScopeGuard::exceptions()
{
s_globalState = 0;
bool caught = false;
@@ -81,5 +172,5 @@ void tst_QScopedGuard::exceptions()
}
-QTEST_MAIN(tst_QScopedGuard)
+QTEST_MAIN(tst_QScopeGuard)
#include "tst_qscopeguard.moc"
diff --git a/tests/auto/corelib/tools/qset/CMakeLists.txt b/tests/auto/corelib/tools/qset/CMakeLists.txt
new file mode 100644
index 0000000000..9e3e33ee7c
--- /dev/null
+++ b/tests/auto/corelib/tools/qset/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qset Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qset LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qset
+ SOURCES
+ tst_qset.cpp
+)
+
+qt_internal_undefine_global_definition(tst_qset QT_NO_JAVA_STYLE_ITERATORS)
diff --git a/tests/auto/corelib/tools/qset/qset.pro b/tests/auto/corelib/tools/qset/qset.pro
deleted file mode 100644
index 3ae4bc4805..0000000000
--- a/tests/auto/corelib/tools/qset/qset.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qset
-QT = core testlib
-qtConfig(c++14): CONFIG += c++14
-qtConfig(c++1z): CONFIG += c++1z
-SOURCES = tst_qset.cpp
-
-DEFINES -= QT_NO_JAVA_STYLE_ITERATORS
diff --git a/tests/auto/corelib/tools/qset/tst_qset.cpp b/tests/auto/corelib/tools/qset/tst_qset.cpp
index 6638ad8b60..116d38112b 100644
--- a/tests/auto/corelib/tools/qset/tst_qset.cpp
+++ b/tests/auto/corelib/tools/qset/tst_qset.cpp
@@ -1,39 +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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <qset.h>
#include <qdebug.h>
int toNumber(const QString &str)
{
int res = 0;
- for (int i = 0; i < str.length(); ++i)
+ for (int i = 0; i < str.size(); ++i)
res = (res * 10) + str[i].digitValue();
return res;
}
@@ -59,8 +34,9 @@ private slots:
void begin();
void end();
void insert();
- void reverseIterators();
+ void insertConstructionCounted();
void setOperations();
+ void setOperationsOnEmptySet();
void stlIterator();
void stlMutableIterator();
void javaIterator();
@@ -69,13 +45,15 @@ private slots:
void initializerList();
void qhash();
void intersects();
+ void find();
+ void values();
};
struct IdentityTracker {
int value, id;
};
-inline uint qHash(IdentityTracker key) { return qHash(key.value); }
+inline size_t qHash(IdentityTracker key) { return qHash(key.value); }
inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; }
void tst_QSet::operator_eq()
@@ -161,43 +139,44 @@ void tst_QSet::size()
QSet<int> set;
QVERIFY(set.size() == 0);
QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
+ QVERIFY(!set.isDetached());
set.insert(1);
QVERIFY(set.size() == 1);
QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
set.insert(1);
QVERIFY(set.size() == 1);
QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
set.insert(2);
QVERIFY(set.size() == 2);
QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
set.remove(1);
QVERIFY(set.size() == 1);
QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
set.remove(1);
QVERIFY(set.size() == 1);
QVERIFY(!set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
set.remove(2);
QVERIFY(set.size() == 0);
QVERIFY(set.isEmpty());
- QVERIFY(set.count() == set.size());
+ QVERIFY(set.size() == set.size());
QVERIFY(set.isEmpty() == set.empty());
}
@@ -206,6 +185,7 @@ void tst_QSet::capacity()
QSet<int> set;
int n = set.capacity();
QVERIFY(n == 0);
+ QVERIFY(!set.isDetached());
for (int i = 0; i < 1000; ++i) {
set.insert(i);
@@ -239,8 +219,12 @@ void tst_QSet::reserve()
void tst_QSet::squeeze()
{
QSet<int> set;
- int n = set.capacity();
- QVERIFY(n == 0);
+ QCOMPARE(set.capacity(), 0);
+
+ set.squeeze();
+ QCOMPARE(set.capacity(), 0);
+
+ QVERIFY(!set.isDetached());
set.reserve(1000);
QVERIFY(set.capacity() >= 1000);
@@ -250,22 +234,37 @@ void tst_QSet::squeeze()
for (int i = 0; i < 500; ++i)
set.insert(i);
- QVERIFY(set.capacity() >= 500 && set.capacity() < 10000);
+ QCOMPARE(set.size(), 500);
+
+ // squeezed capacity for 500 elements
+ qsizetype capacity = set.capacity(); // current implementation: 512
+ QCOMPARE_GE(capacity, set.size());
set.reserve(50000);
- QVERIFY(set.capacity() >= 50000);
+ QVERIFY(set.capacity() >= 50000); // current implementation: 65536
set.squeeze();
- QVERIFY(set.capacity() < 500);
+ QCOMPARE(set.capacity(), capacity);
+ // removing elements does not shed capacity
set.remove(499);
- QVERIFY(set.capacity() < 500);
+ QCOMPARE(set.capacity(), capacity);
set.insert(499);
- QVERIFY(set.capacity() >= 500);
+ QCOMPARE(set.capacity(), capacity);
+
+ // grow it beyond the current capacity
+ for (int i = set.size(); i <= capacity; ++i)
+ set.insert(i);
+ QCOMPARE(set.size(), capacity + 1);
+ QCOMPARE_GT(set.capacity(), capacity + 1);// current implementation: 2 * capacity (1024)
for (int i = 0; i < 500; ++i)
set.remove(i);
+
+ // removing elements does not shed capacity
+ QCOMPARE_GT(set.capacity(), capacity + 1);
+
set.squeeze();
QVERIFY(set.capacity() < 100);
}
@@ -309,6 +308,7 @@ void tst_QSet::clear()
set1.clear();
QVERIFY(set1.size() == 0);
+ QVERIFY(!set1.isDetached());
set1.insert("foo");
QVERIFY(set1.size() != 0);
@@ -326,10 +326,9 @@ void tst_QSet::clear()
void tst_QSet::cpp17ctad()
{
-#ifdef __cpp_deduction_guides
#define QVERIFY_IS_SET_OF(obj, Type) \
QVERIFY2((std::is_same<decltype(obj), QSet<Type>>::value), \
- QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>()))
+ QMetaType::fromType<decltype(obj)::value_type>().name())
#define CHECK(Type, One, Two, Three) \
do { \
const Type v[] = {One, Two, Three}; \
@@ -346,29 +345,36 @@ void tst_QSet::cpp17ctad()
CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
#undef QVERIFY_IS_SET_OF
#undef CHECK
-#else
- QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler.");
-#endif
}
void tst_QSet::remove()
{
- QSet<QString> set1;
+ QSet<QString> set;
+ QCOMPARE(set.remove("test"), false);
+ QVERIFY(!set.isDetached());
+
+ const auto cnt = set.removeIf([](auto it) {
+ Q_UNUSED(it);
+ return true;
+ });
+ QCOMPARE(cnt, 0);
for (int i = 0; i < 500; ++i)
- set1.insert(QString::number(i));
+ set.insert(QString::number(i));
- QCOMPARE(set1.size(), 500);
+ QCOMPARE(set.size(), 500);
for (int j = 0; j < 500; ++j) {
- set1.remove(QString::number((j * 17) % 500));
- QCOMPARE(set1.size(), 500 - j - 1);
+ set.remove(QString::number((j * 17) % 500));
+ QCOMPARE(set.size(), 500 - j - 1);
}
}
void tst_QSet::contains()
{
QSet<QString> set1;
+ QVERIFY(!set1.contains("test"));
+ QVERIFY(!set1.isDetached());
for (int i = 0; i < 500; ++i) {
QVERIFY(!set1.contains(QString::number(i)));
@@ -393,6 +399,7 @@ void tst_QSet::containsSet()
// empty set contains the empty set
QVERIFY(set1.contains(set2));
+ QVERIFY(!set1.isDetached());
for (int i = 0; i < 500; ++i) {
set1.insert(QString::number(i));
@@ -414,6 +421,7 @@ void tst_QSet::containsSet()
// the empty set doesn't contain a filled set
QVERIFY(!set3.contains(set1));
+ QVERIFY(!set3.isDetached());
// verify const signature
const QSet<QString> set4;
@@ -435,6 +443,8 @@ void tst_QSet::begin()
QVERIFY(k == ell);
QVERIFY(i == k);
QVERIFY(j == ell);
+ QVERIFY(!set1.isDetached());
+ QVERIFY(!set2.isDetached());
}
set1.insert(44);
@@ -464,6 +474,31 @@ void tst_QSet::begin()
QVERIFY(i == k);
QVERIFY(j == ell);
}
+
+ const QSet<int> set3;
+ QSet<int> set4 = set3;
+
+ {
+ QSet<int>::const_iterator i = set3.begin();
+ QSet<int>::const_iterator j = set3.cbegin();
+ QSet<int>::const_iterator k = set4.begin();
+ QVERIFY(i == j);
+ QVERIFY(k == j);
+ QVERIFY(!set3.isDetached());
+ QVERIFY(set4.isDetached());
+ }
+
+ set4.insert(1);
+
+ {
+ QSet<int>::const_iterator i = set3.begin();
+ QSet<int>::const_iterator j = set3.cbegin();
+ QSet<int>::const_iterator k = set4.begin();
+ QVERIFY(i == j);
+ QVERIFY(k != j);
+ QVERIFY(!set3.isDetached());
+ QVERIFY(set4.isDetached());
+ }
}
void tst_QSet::end()
@@ -484,6 +519,9 @@ void tst_QSet::end()
QVERIFY(set1.constBegin() == set1.constEnd());
QVERIFY(set2.constBegin() == set2.constEnd());
+
+ QVERIFY(!set1.isDetached());
+ QVERIFY(!set2.isDetached());
}
set1.insert(44);
@@ -496,13 +534,13 @@ void tst_QSet::end()
QVERIFY(i == j);
QVERIFY(k == ell);
- QVERIFY(i != k);
- QVERIFY(j != ell);
QVERIFY(set1.constBegin() != set1.constEnd());
QVERIFY(set2.constBegin() == set2.constEnd());
+ QVERIFY(set1.constBegin() != set2.constBegin());
}
+
set2 = set1;
{
@@ -524,6 +562,37 @@ void tst_QSet::end()
set2.clear();
QVERIFY(set1.constBegin() == set1.constEnd());
QVERIFY(set2.constBegin() == set2.constEnd());
+
+ const QSet<int> set3;
+ QSet<int> set4 = set3;
+
+ {
+ QSet<int>::const_iterator i = set3.end();
+ QSet<int>::const_iterator j = set3.cend();
+ QSet<int>::const_iterator k = set4.end();
+ QVERIFY(i == j);
+ QVERIFY(k == j);
+ QVERIFY(!set3.isDetached());
+ QVERIFY(!set4.isDetached());
+
+ QVERIFY(set3.constBegin() == set3.constEnd());
+ QVERIFY(set4.constBegin() == set4.constEnd());
+ }
+
+ set4.insert(1);
+
+ {
+ QSet<int>::const_iterator i = set3.end();
+ QSet<int>::const_iterator j = set3.cend();
+ QSet<int>::const_iterator k = set4.end();
+ QVERIFY(i == j);
+ QVERIFY(k == j);
+ QVERIFY(!set3.isDetached());
+ QVERIFY(set4.isDetached());
+
+ QVERIFY(set3.constBegin() == set3.constEnd());
+ QVERIFY(set4.constBegin() != set4.constEnd());
+ }
}
void tst_QSet::insert()
@@ -577,19 +646,82 @@ void tst_QSet::insert()
}
}
-void tst_QSet::reverseIterators()
+struct ConstructionCounted
{
- QSet<int> s;
- s << 1 << 17 << 61 << 127 << 911;
- std::vector<int> v(s.begin(), s.end());
- std::reverse(v.begin(), v.end());
- const QSet<int> &cs = s;
- QVERIFY(std::equal(v.begin(), v.end(), s.rbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), s.crbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), cs.rbegin()));
- QVERIFY(std::equal(s.rbegin(), s.rend(), v.begin()));
- QVERIFY(std::equal(s.crbegin(), s.crend(), v.begin()));
- QVERIFY(std::equal(cs.rbegin(), cs.rend(), v.begin()));
+ ConstructionCounted(int i) : i(i) { }
+ ConstructionCounted(ConstructionCounted &&other) noexcept
+ : i(other.i), copies(other.copies), moves(other.moves + 1)
+ {
+ // set to some easily noticeable values
+ other.i = -64;
+ other.copies = -64;
+ other.moves = -64;
+ }
+ ConstructionCounted &operator=(ConstructionCounted &&other) noexcept
+ {
+ ConstructionCounted moved = std::move(other);
+ std::swap(*this, moved);
+ return *this;
+ }
+ ConstructionCounted(const ConstructionCounted &other) noexcept
+ : i(other.i), copies(other.copies + 1), moves(other.moves)
+ {
+ }
+ ConstructionCounted &operator=(const ConstructionCounted &other) noexcept
+ {
+ ConstructionCounted copy = other;
+ std::swap(*this, copy);
+ return *this;
+ }
+ ~ConstructionCounted() = default;
+
+ friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs)
+ {
+ return lhs.i == rhs.i;
+ }
+
+ QString toString() { return QString::number(i); }
+
+ int i;
+ int copies = 0;
+ int moves = 0;
+};
+
+size_t qHash(const ConstructionCounted &c, std::size_t seed = 0)
+{
+ return qHash(c.i, seed);
+}
+
+void tst_QSet::insertConstructionCounted()
+{
+ QSet<ConstructionCounted> set;
+
+ // copy-insert
+ ConstructionCounted toCopy(7);
+ auto inserted = set.insert(toCopy);
+ QCOMPARE(set.size(), 1);
+ auto element = set.begin();
+ QCOMPARE(inserted, element);
+ QCOMPARE(inserted->copies, 1);
+ QCOMPARE(inserted->moves, 1);
+ QCOMPARE(inserted->i, 7);
+
+ // move-insert
+ ConstructionCounted toMove(8);
+ inserted = set.insert(std::move(toMove));
+ element = set.find(8);
+ QCOMPARE(set.size(), 2);
+ QVERIFY(element != set.end());
+ QCOMPARE(inserted, element);
+ QCOMPARE(inserted->copies, 0);
+ QCOMPARE(inserted->moves, 1);
+ QCOMPARE(inserted->i, 8);
+
+ inserted = set.insert(std::move(toCopy)); // move-insert an existing value
+ QCOMPARE(set.size(), 2);
+ // The previously existing key is used as they compare equal:
+ QCOMPARE(inserted->copies, 1);
+ QCOMPARE(inserted->moves, 1);
}
void tst_QSet::setOperations()
@@ -690,6 +822,44 @@ void tst_QSet::setOperations()
QVERIFY(set18 == set8);
}
+void tst_QSet::setOperationsOnEmptySet()
+{
+ {
+ // Both sets are empty
+ QSet<int> set1;
+ QSet<int> set2;
+
+ set1.unite(set2);
+ QVERIFY(set1.isEmpty());
+ QVERIFY(!set1.isDetached());
+
+ set1.intersect(set2);
+ QVERIFY(set1.isEmpty());
+ QVERIFY(!set1.isDetached());
+
+ set1.subtract(set2);
+ QVERIFY(set1.isEmpty());
+ QVERIFY(!set1.isDetached());
+ }
+ {
+ // Second set is not empty
+ QSet<int> empty;
+ QSet<int> nonEmpty { 1, 2, 3 };
+
+ empty.intersect(nonEmpty);
+ QVERIFY(empty.isEmpty());
+ QVERIFY(!empty.isDetached());
+
+ empty.subtract(nonEmpty);
+ QVERIFY(empty.isEmpty());
+ QVERIFY(!empty.isDetached());
+
+ empty.unite(nonEmpty);
+ QCOMPARE(empty, nonEmpty);
+ QVERIFY(!empty.isDetached());
+ }
+}
+
void tst_QSet::stlIterator()
{
QSet<QString> set1;
@@ -705,16 +875,6 @@ void tst_QSet::stlIterator()
}
QVERIFY(sum == 24999 * 25000 / 2);
}
-
- {
- int sum = 0;
- QSet<QString>::const_iterator i = set1.end();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
}
void tst_QSet::stlMutableIterator()
@@ -734,21 +894,10 @@ void tst_QSet::stlMutableIterator()
}
{
- int sum = 0;
- QSet<QString>::iterator i = set1.end();
- while (i != set1.begin()) {
- --i;
- sum += toNumber(*i);
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
QSet<QString> set2 = set1;
QSet<QString> set3 = set2;
QSet<QString>::iterator i = set2.begin();
- QSet<QString>::iterator j = set3.begin();
while (i != set2.end()) {
i = set2.erase(i);
@@ -756,24 +905,7 @@ void tst_QSet::stlMutableIterator()
QVERIFY(set2.isEmpty());
QVERIFY(!set3.isEmpty());
- j = set3.end();
- while (j != set3.begin()) {
- j--;
- if (j + 1 != set3.end())
- set3.erase(j + 1);
- }
- if (set3.begin() != set3.end())
- set3.erase(set3.begin());
-
- QVERIFY(set2.isEmpty());
- QVERIFY(set3.isEmpty());
-
-// #if QT_VERSION >= 0x050000
-// i = set2.insert("foo");
-// #else
- QSet<QString>::const_iterator k = set2.insert("foo");
- i = reinterpret_cast<QSet<QString>::iterator &>(k);
-// #endif
+ i = set2.insert("foo");
QCOMPARE(*i, QLatin1String("foo"));
}
}
@@ -802,59 +934,16 @@ void tst_QSet::javaIterator()
QVERIFY(sum == 24999 * 25000 / 2);
}
- {
- int sum = 0;
- QSetIterator<QString> i(set1);
- while (i.hasNext()) {
- i.next();
- sum += toNumber(i.peekPrevious());
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious())
- sum += toNumber(i.previous());
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious()) {
- sum += toNumber(i.peekPrevious());
- i.previous();
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious()) {
- i.previous();
- sum += toNumber(i.peekNext());
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
int sum1 = 0;
int sum2 = 0;
QSetIterator<QString> i(set1);
QSetIterator<QString> j(set1);
- int n = 0;
while (i.hasNext()) {
QVERIFY(j.hasNext());
set1.remove(i.peekNext());
sum1 += toNumber(i.next());
sum2 += toNumber(j.next());
- ++n;
}
QVERIFY(!j.hasNext());
QVERIFY(sum1 == 24999 * 25000 / 2);
@@ -897,52 +986,10 @@ void tst_QSet::javaMutableIterator()
}
{
- int sum = 0;
- QMutableSetIterator<QString> i(set1);
- while (i.hasNext()) {
- i.next();
- sum += toNumber(i.peekPrevious());
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QMutableSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious())
- sum += toNumber(i.previous());
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QMutableSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious()) {
- sum += toNumber(i.peekPrevious());
- i.previous();
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
- int sum = 0;
- QMutableSetIterator<QString> i(set1);
- i.toBack();
- while (i.hasPrevious()) {
- i.previous();
- sum += toNumber(i.peekNext());
- }
- QVERIFY(sum == 24999 * 25000 / 2);
- }
-
- {
QSet<QString> set2 = set1;
QSet<QString> set3 = set2;
QMutableSetIterator<QString> i(set2);
- QMutableSetIterator<QString> j(set3);
while (i.hasNext()) {
i.next();
@@ -950,14 +997,6 @@ void tst_QSet::javaMutableIterator()
}
QVERIFY(set2.isEmpty());
QVERIFY(!set3.isEmpty());
-
- j.toBack();
- while (j.hasPrevious()) {
- j.previous();
- j.remove();
- }
- QVERIFY(set2.isEmpty());
- QVERIFY(set3.isEmpty());
}
}
@@ -982,7 +1021,7 @@ void tst_QSet::makeSureTheComfortFunctionsCompile()
void tst_QSet::initializerList()
{
QSet<int> set = {1, 1, 2, 3, 4, 5};
- QCOMPARE(set.count(), 5);
+ QCOMPARE(set.size(), 5);
QVERIFY(set.contains(1));
QVERIFY(set.contains(2));
QVERIFY(set.contains(3));
@@ -991,7 +1030,7 @@ void tst_QSet::initializerList()
// check _which_ of the equal elements gets inserted (in the QHash/QMap case, it's the last):
const QSet<IdentityTracker> set2 = {{1, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
- QCOMPARE(set2.count(), 5);
+ QCOMPARE(set2.size(), 5);
const int dummy = -1;
const IdentityTracker searchKey = {1, dummy};
QCOMPARE(set2.find(searchKey)->id, 0);
@@ -1010,23 +1049,33 @@ void tst_QSet::qhash()
//
{
// create some deterministic initial state:
- qSetGlobalQHashSeed(0);
+ QHashSeed::setDeterministicGlobalSeed();
QSet<int> s1;
s1.reserve(4);
s1 << 400 << 300 << 200 << 100;
- // also change the seed:
- qSetGlobalQHashSeed(0x10101010);
+ int retries = 128;
+ while (--retries >= 0) {
+ // reset the global seed to something different
+ QHashSeed::resetRandomGlobalSeed();
+
+ QSet<int> s2;
+ s2.reserve(100); // provoke different bucket counts
+ s2 << 100 << 200 << 300 << 400; // and insert elements in different order, too
+ QVERIFY(s1.capacity() != s2.capacity());
- QSet<int> s2;
- s2.reserve(100); // provoke different bucket counts
- s2 << 100 << 200 << 300 << 400; // and insert elements in different order, too
+ // see if we got a _different_ order
+ if (std::equal(s1.cbegin(), s1.cend(), s2.cbegin()))
+ continue;
- QVERIFY(s1.capacity() != s2.capacity());
- QCOMPARE(s1, s2);
- QVERIFY(!std::equal(s1.cbegin(), s1.cend(), s2.cbegin())); // verify that the order _is_ different
- QCOMPARE(qHash(s1), qHash(s2));
+ // check if the two QHashes still compare equal and produce the
+ // same hash, despite containing elements in different orders
+ QCOMPARE(s1, s2);
+ QCOMPARE(qHash(s1), qHash(s2));
+ }
+ QVERIFY2(retries != 0, "Could not find a QSet with a different order of elements even "
+ "after a lot of retries. This is unlikely, but possible.");
}
//
@@ -1045,6 +1094,8 @@ void tst_QSet::intersects()
QVERIFY(!s1.intersects(s1));
QVERIFY(!s1.intersects(s2));
+ QVERIFY(!s1.isDetached());
+ QVERIFY(!s2.isDetached());
s1 << 100;
QVERIFY(s1.intersects(s1));
@@ -1056,7 +1107,7 @@ void tst_QSet::intersects()
s1 << 200;
QVERIFY(s1.intersects(s2));
- qSetGlobalQHashSeed(0x10101010);
+ QHashSeed::resetRandomGlobalSeed();
QSet<int> s3;
s3 << 500;
QVERIFY(!s1.intersects(s3));
@@ -1064,6 +1115,50 @@ void tst_QSet::intersects()
QVERIFY(s1.intersects(s3));
}
+void tst_QSet::find()
+{
+ QSet<int> set;
+ QCOMPARE(set.find(1), set.end());
+ QCOMPARE(set.constFind(1), set.constEnd());
+ QVERIFY(!set.isDetached());
+
+ set.insert(1);
+ set.insert(2);
+
+ QVERIFY(set.find(1) != set.end());
+ QVERIFY(set.constFind(2) != set.constEnd());
+ QVERIFY(set.find(3) == set.end());
+ QVERIFY(set.constFind(4) == set.constEnd());
+}
+
+template<typename T>
+QList<T> sorted(const QList<T> &list)
+{
+ QList<T> res = list;
+ std::sort(res.begin(), res.end());
+ return res;
+}
+
+void tst_QSet::values()
+{
+ QSet<int> set;
+ QVERIFY(set.values().isEmpty());
+ QVERIFY(!set.isDetached());
+
+ set.insert(1);
+ QCOMPARE(set.values(), QList<int> { 1 });
+
+ set.insert(10);
+ set.insert(5);
+ set.insert(2);
+
+ QCOMPARE(sorted(set.values()), QList<int>({ 1, 2, 5, 10 }));
+
+ set.remove(5);
+
+ QCOMPARE(sorted(set.values()), QList<int>({ 1, 2, 10 }));
+}
+
QTEST_APPLESS_MAIN(tst_QSet)
#include "tst_qset.moc"
diff --git a/tests/auto/corelib/tools/qsharedpointer/CMakeLists.txt b/tests/auto/corelib/tools/qsharedpointer/CMakeLists.txt
new file mode 100644
index 0000000000..0db0cba4c0
--- /dev/null
+++ b/tests/auto/corelib/tools/qsharedpointer/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qsharedpointer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsharedpointer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qsharedpointer
+ SOURCES
+ forwarddeclared.cpp
+ nontracked.cpp
+ wrapper.cpp
+ tst_qsharedpointer.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
index d1bb89f549..c676924668 100644
--- a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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 "externaltests.h"
@@ -80,32 +55,34 @@ namespace QTest {
{
if (process.state() == QProcess::Running) {
process.terminate();
- QThread::msleep(20);
+ QThread::sleep(std::chrono::milliseconds{20});
if (process.state() == QProcess::Running)
process.kill();
}
}
+# ifdef Q_OS_UNIX
class QExternalProcess: public QProcess
{
- protected:
-#ifdef Q_OS_UNIX
- void setupChildProcess()
+ public:
+ QExternalProcess()
{
- // run in user code
- QProcess::setupChildProcess();
-
- if (processChannelMode() == ForwardedChannels) {
- // reopen /dev/tty into stdin
- int fd = ::open("/dev/tty", O_RDONLY);
- if (fd == -1)
- return;
- ::dup2(fd, 0);
- ::close(fd);
- }
+ setChildProcessModifier([this]() {
+ // run in user code
+ if (processChannelMode() == ForwardedChannels) {
+ // reopen /dev/tty into stdin
+ int fd = ::open("/dev/tty", O_RDONLY);
+ if (fd == -1)
+ return;
+ ::dup2(fd, 0);
+ ::close(fd);
+ }
+ });
}
-#endif
};
+# else
+ using QExternalProcess = QProcess;
+# endif
#endif // QT_CONFIG(process)
class QExternalTestPrivate
@@ -341,7 +318,7 @@ namespace QTest {
if (qtModules & QExternalTest::QtScript)
sourceCode += "#include <QtScript/QtScript>\n";
if (qtModules & QExternalTest::QtTest)
- sourceCode += "#include <QtTest/QtTest>\n";
+ sourceCode += "#include <QTest>\n";
if (qtModules & QExternalTest::QtDBus)
sourceCode += "#include <QtDBus/QtDBus>\n";
if (qtModules & QExternalTest::QtWebKit)
@@ -360,7 +337,7 @@ namespace QTest {
"}\n"
"\n"
"#ifdef Q_OS_WIN\n"
- "#include <windows.h>\n"
+ "#include <qt_windows.h>\n"
"#if defined(Q_CC_MSVC)\n"
"#include <crtdbg.h>\n"
"#endif\n"
@@ -588,7 +565,7 @@ namespace QTest {
<< QLatin1String("project.pro");
qmake.setWorkingDirectory(temporaryDirPath);
- QString cmd = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake";
+ QString cmd = QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qmake";
#ifdef Q_OS_WIN
cmd.append(".exe");
#endif
diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.h b/tests/auto/corelib/tools/qsharedpointer/externaltests.h
index bae6adaefe..790ca61992 100644
--- a/tests/auto/corelib/tools/qsharedpointer/externaltests.h
+++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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
#ifndef QTEST_EXTERNAL_TESTS_H
diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.pri b/tests/auto/corelib/tools/qsharedpointer/externaltests.pri
deleted file mode 100644
index 604bd7f59f..0000000000
--- a/tests/auto/corelib/tools/qsharedpointer/externaltests.pri
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += $$PWD/externaltests.cpp
-HEADERS += $$PWD/externaltests.h
-cleanedQMAKESPEC = $$replace(QMAKESPEC, \\\\, /)
-DEFINES += DEFAULT_MAKESPEC=\\\"$$cleanedQMAKESPEC\\\"
-
-cross_compile:DEFINES += QTEST_NO_RTTI QTEST_CROSS_COMPILED
diff --git a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp
index df343b5ebc..5a0af60c11 100644
--- a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.cpp
@@ -1,31 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "forwarddeclared.h"
#include "qsharedpointer.h"
diff --git a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h
index c72324841c..ba436d99cf 100644
--- a/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h
+++ b/tests/auto/corelib/tools/qsharedpointer/forwarddeclared.h
@@ -1,31 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef FORWARDDECLARED_H
#define FORWARDDECLARED_H
diff --git a/tests/auto/corelib/tools/qsharedpointer/nontracked.cpp b/tests/auto/corelib/tools/qsharedpointer/nontracked.cpp
index e0780f8a9a..b572fa1b9f 100644
--- a/tests/auto/corelib/tools/qsharedpointer/nontracked.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/nontracked.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** 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 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
/*
* This file exists because tst_qsharedpointer.cpp is compiled with
@@ -40,7 +15,7 @@
*/
#include <qsharedpointer.h>
-#include <QtTest>
+#include <QTest>
#include "nontracked.h"
diff --git a/tests/auto/corelib/tools/qsharedpointer/nontracked.h b/tests/auto/corelib/tools/qsharedpointer/nontracked.h
index 76af80d2d7..e10ea08a4d 100644
--- a/tests/auto/corelib/tools/qsharedpointer/nontracked.h
+++ b/tests/auto/corelib/tools/qsharedpointer/nontracked.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Intel Corporation.
-** 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 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef NONTRACKED_H
#define NONTRACKED_H
diff --git a/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro b/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro
deleted file mode 100644
index 240137d563..0000000000
--- a/tests/auto/corelib/tools/qsharedpointer/qsharedpointer.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qsharedpointer
-QT = core testlib
-
-SOURCES = tst_qsharedpointer.cpp \
- forwarddeclared.cpp \
- nontracked.cpp \
- wrapper.cpp
-
-HEADERS = forwarddeclared.h \
- nontracked.h \
- wrapper.h
-
-TESTDATA += forwarddeclared.cpp forwarddeclared.h
-
-include(externaltests.pri)
-DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
index a9fd282ac9..f42637a3fe 100644
--- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
@@ -1,41 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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) 2021 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2021 Klarälvdalens Datakonsult AB.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#define QT_SHAREDPOINTER_TRACK_POINTERS
#include "qsharedpointer.h"
-#include <QtTest/QtTest>
+#include <QTest>
+#include <QPointer>
+#include <QRandomGenerator>
#include <QtCore/QHash>
+#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QThread>
-#include <QtCore/QVector>
+#include <QtCore/private/qvolatile_p.h>
-#include "externaltests.h"
#include "forwarddeclared.h"
#include "nontracked.h"
#include "wrapper.h"
@@ -45,7 +23,7 @@
#include <stdlib.h>
#include <time.h>
-#ifdef Q_OS_UNIX
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
#include <sys/resource.h>
#endif
@@ -76,10 +54,6 @@ private slots:
void functionCallDownCast();
void upCast();
void qobjectWeakManagement();
-#if QT_DEPRECATED_SINCE(5, 0)
- void noSharedPointerFromWeakQObject();
- void sharedPointerFromQObjectWithWeak();
-#endif
void weakQObjectFromSharedPointer();
void objectCast();
void objectCastStdSharedPtr();
@@ -95,6 +69,7 @@ private slots:
void constCorrectness();
void customDeleter();
void lambdaCustomDeleter();
+ void customDeleterOnNullptr();
void creating();
void creatingCvQualified();
void creatingVariadic();
@@ -112,9 +87,11 @@ private slots:
void threadStressTest_data();
void threadStressTest();
void validConstructs();
+#if 0
void invalidConstructs_data();
void invalidConstructs();
-
+#endif
+ void ownerComparisons();
// let invalidConstructs be the last test, because it's the slowest;
// add new tests above this block
@@ -132,7 +109,7 @@ public:
void tst_QSharedPointer::initTestCase()
{
-#if defined(Q_OS_UNIX)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
// The tests create a lot of threads, which require file descriptors. On systems like
// OS X low defaults such as 256 as the limit for the number of simultaneously
// open files is not sufficient.
@@ -153,7 +130,7 @@ QtSharedPointer::ExternalRefCountData *refCountData(const QSharedPointer<T> &b)
QtSharedPointer::ExternalRefCountData* data;
};
// sanity checks:
- Q_STATIC_ASSERT(sizeof(QSharedPointer<T>) == sizeof(Dummy));
+ static_assert(sizeof(QSharedPointer<T>) == sizeof(Dummy));
Q_ASSERT(static_cast<const Dummy*>(static_cast<const void*>(&b))->value == b.data());
return static_cast<const Dummy*>(static_cast<const void*>(&b))->data;
}
@@ -341,6 +318,11 @@ void tst_QSharedPointer::basics()
QCOMPARE(!weak, isNull);
QCOMPARE(bool(weak), !isNull);
+ QCOMPARE(weak.isNull(), (weak == nullptr));
+ QCOMPARE(weak.isNull(), (nullptr == weak));
+ QCOMPARE(!weak.isNull(), (weak != nullptr));
+ QCOMPARE(!weak.isNull(), (nullptr != weak));
+
QVERIFY(ptr == weak);
QVERIFY(weak == ptr);
QVERIFY(! (ptr != weak));
@@ -426,6 +408,12 @@ void tst_QSharedPointer::nullptrOps()
QVERIFY(!p2.get());
QVERIFY(p1 == p2);
+ QWeakPointer<char> wp1 = p1;
+ QVERIFY(wp1 == nullptr);
+ QVERIFY(nullptr == wp1);
+ QCOMPARE(wp1, nullptr);
+ QCOMPARE(nullptr, wp1);
+
QSharedPointer<char> p3 = p1;
QVERIFY(p3 == p1);
QVERIFY(p3 == null);
@@ -452,6 +440,10 @@ void tst_QSharedPointer::nullptrOps()
QVERIFY(p4 != p2);
QVERIFY(p4 != null);
QVERIFY(p4 != p3);
+
+ QWeakPointer<char> wp2 = p4;
+ QVERIFY(wp2 != nullptr);
+ QVERIFY(nullptr != wp2);
}
void tst_QSharedPointer::swap()
@@ -594,6 +586,9 @@ void tst_QSharedPointer::useOfForwardDeclared()
void tst_QSharedPointer::memoryManagement()
{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
+
int generation = Data::generationCounter + 1;
int destructorCounter = Data::destructorCounter;
@@ -655,6 +650,7 @@ void tst_QSharedPointer::memoryManagement()
QVERIFY(ptr.isNull());
QVERIFY(ptr == 0);
QCOMPARE(ptr.data(), (Data*)0);
+QT_WARNING_POP
}
void tst_QSharedPointer::dropLastReferenceOfForwardDeclared()
@@ -740,12 +736,12 @@ public:
DerivedData() : moreData(0) { }
~DerivedData() { ++derivedDestructorCounter; }
- virtual void virtualDelete()
+ void virtualDelete() override
{
delete this;
}
- virtual int classLevel() { return 2; }
+ int classLevel() override { return 2; }
};
int DerivedData::derivedDestructorCounter = 0;
@@ -760,7 +756,7 @@ public:
class DiffPtrDerivedData: public Stuffing, public Data
{
public:
- virtual int classLevel() { return 3; }
+ int classLevel() override { return 3; }
};
class VirtualDerived: virtual public Data
@@ -769,15 +765,20 @@ public:
int moreData;
VirtualDerived() : moreData(0xc0ffee) { }
- virtual int classLevel() { return 4; }
+ int classLevel() override { return 4; }
};
void tst_QSharedPointer::downCast()
{
{
+ // copy construction
QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QSharedPointer<DerivedData> copy = ptr;
QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(ptr);
QSharedPointer<Data> other;
+ QWeakPointer<DerivedData> weak = ptr;
+ QWeakPointer<Data> baseweak = qSharedPointerCast<Data>(ptr);
+ QWeakPointer<Data> baseweak2 = qSharedPointerCast<Data>(weak);
QVERIFY(ptr == baseptr);
QVERIFY(baseptr == ptr);
@@ -788,11 +789,55 @@ void tst_QSharedPointer::downCast()
QVERIFY(other != ptr);
QVERIFY(! (ptr == other));
QVERIFY(! (other == ptr));
+
+ // copy assignments
+ baseptr = qSharedPointerCast<Data>(ptr);
+ baseweak = qSharedPointerCast<Data>(ptr);
+ baseweak2 = baseweak;
+
+ // move assignments (these don't actually move)
+ baseptr = qSharedPointerCast<Data>(std::move(ptr));
+ ptr = copy;
+ baseweak = qSharedPointerCast<Data>(std::move(ptr));
+ ptr = copy;
+ baseweak2 = qSharedPointerCast<Data>(std::move(baseweak));
+
+ // move construction (these don't actually move)
+ ptr = copy;
+ QSharedPointer<Data> ptr3(qSharedPointerCast<Data>(std::move(ptr)));
+ ptr = copy;
+ QWeakPointer<Data> baseweak3(qSharedPointerCast<Data>(std::move(ptr)));
+ ptr = copy;
+ QWeakPointer<Data> baseweak4(qSharedPointerCast<Data>(std::move(weak)));
}
{
+ // copy construction
QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
+ QSharedPointer<DerivedData> copy = ptr;
QSharedPointer<Data> baseptr = ptr;
+ QWeakPointer<DerivedData> weak = ptr;
+ QWeakPointer<Data> baseweak = ptr;
+ QWeakPointer<Data> baseweak2 = weak;
+
+ // copy assignments
+ baseptr = ptr;
+ baseweak = ptr;
+ baseweak2 = weak;
+
+ // move assignments (only the QSharedPointer-QSharedPointer actually moves)
+ baseweak = std::move(ptr);
+ baseweak2 = std::move(weak);
+ ptr = copy;
+ baseptr = std::move(ptr);
+
+ // move construction (only the QSharedPointer-QSharedPointer actually moves)
+ ptr = copy;
+ QWeakPointer<Data> baseweak3(std::move(ptr));
+ ptr = copy;
+ QWeakPointer<Data> baseweak4(std::move(weak));
+ ptr = copy;
+ QSharedPointer<Data> baseptr2(std::move(ptr));
}
int destructorCount;
@@ -954,156 +999,10 @@ void tst_QSharedPointer::qobjectWeakManagement()
QVERIFY(weak.isNull());
}
safetyCheck();
-
-#if QT_DEPRECATED_SINCE(5, 0)
- {
- QWeakPointer<QObject> weak;
- weak = QWeakPointer<QObject>();
- QVERIFY(weak.isNull());
- QVERIFY(!weak.data());
- }
-
- {
- QObject *obj = new QObject;
- QWeakPointer<QObject> weak(obj);
- QVERIFY(!weak.isNull());
- QVERIFY(weak.data() == obj);
-
- // now delete
- delete obj;
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-
- {
- // same, bit with operator=
- QObject *obj = new QObject;
- QWeakPointer<QObject> weak;
- weak = obj;
- QVERIFY(!weak.isNull());
- QVERIFY(weak.data() == obj);
-
- // now delete
- delete obj;
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-
- {
- // delete triggered by parent
- QObject *obj, *parent;
- parent = new QObject;
- obj = new QObject(parent);
- QWeakPointer<QObject> weak(obj);
-
- // now delete the parent
- delete parent;
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-
- {
- // same as above, but set the parent after QWeakPointer is created
- QObject *obj, *parent;
- obj = new QObject;
- QWeakPointer<QObject> weak(obj);
-
- parent = new QObject;
- obj->setParent(parent);
-
- // now delete the parent
- delete parent;
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-
- {
- // with two QWeakPointers
- QObject *obj = new QObject;
- QWeakPointer<QObject> weak(obj);
-
- {
- QWeakPointer<QObject> weak2(obj);
- QVERIFY(!weak2.isNull());
- QVERIFY(weak == weak2);
- }
- QVERIFY(!weak.isNull());
-
- delete obj;
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-
- {
- // same, but delete the pointer while two QWeakPointers exist
- QObject *obj = new QObject;
- QWeakPointer<QObject> weak(obj);
-
- {
- QWeakPointer<QObject> weak2(obj);
- QVERIFY(!weak2.isNull());
-
- delete obj;
- QVERIFY(weak.isNull());
- QVERIFY(weak2.isNull());
- }
- QVERIFY(weak.isNull());
- }
- safetyCheck();
-#endif
}
-#if QT_DEPRECATED_SINCE(5, 0)
-void tst_QSharedPointer::noSharedPointerFromWeakQObject()
-{
- // you're not allowed to create a QSharedPointer from an unmanaged QObject
- QObject obj;
- QWeakPointer<QObject> weak(&obj);
-
- {
- QTest::ignoreMessage(QtWarningMsg , "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
- QSharedPointer<QObject> strong = weak.toStrongRef();
- QVERIFY(strong.isNull());
- }
- {
- QTest::ignoreMessage(QtWarningMsg , "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
- QSharedPointer<QObject> strong = weak;
- QVERIFY(strong.isNull());
- }
-
- QCOMPARE(weak.data(), &obj);
- // if something went wrong, we'll probably crash here
-}
-
-void tst_QSharedPointer::sharedPointerFromQObjectWithWeak()
-{
- QObject *ptr = new QObject;
- QWeakPointer<QObject> weak = ptr;
- {
- QSharedPointer<QObject> shared(ptr);
- QVERIFY(!weak.isNull());
- QCOMPARE(shared.data(), ptr);
- QCOMPARE(weak.data(), ptr);
- }
- QVERIFY(weak.isNull());
-}
-#endif
-
void tst_QSharedPointer::weakQObjectFromSharedPointer()
{
-#if QT_DEPRECATED_SINCE(5, 0)
- {
- // this is the inverse of the above: you're allowed to create a QWeakPointer
- // from a managed QObject
- QSharedPointer<QObject> shared(new QObject);
- QWeakPointer<QObject> weak = shared.data();
- QVERIFY(!weak.isNull());
-
- // delete:
- shared.clear();
- QVERIFY(weak.isNull());
- }
-#endif
{
QSharedPointer<QObject> shared(new QObject);
QWeakPointer<QObject> weak = shared;
@@ -1377,6 +1276,22 @@ void tst_QSharedPointer::virtualBaseDifferentPointers()
QVERIFY(baseptr == aBase);
}
safetyCheck();
+ {
+ VirtualDerived *aData = new VirtualDerived;
+
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
+ QWeakPointer<VirtualDerived> wptr = ptr;
+
+ ptr.reset();
+ QVERIFY(wptr.toStrongRef().isNull());
+
+ QWeakPointer<Data> wptr2 = wptr;
+ QVERIFY(wptr2.toStrongRef().isNull());
+
+ QWeakPointer<Data> wptr3 = std::move(wptr);
+ QVERIFY(wptr3.toStrongRef().isNull());
+ }
+ safetyCheck();
}
#ifndef QTEST_NO_RTTI
@@ -1846,6 +1761,33 @@ void tst_QSharedPointer::lambdaCustomDeleter()
safetyCheck();
}
+void tst_QSharedPointer::customDeleterOnNullptr()
+{
+ Data *null = nullptr;
+ int callCount = 0;
+ auto deleter = [&callCount](Data *) { ++callCount; };
+ {
+ QSharedPointer<Data> ptr(null, deleter);
+ }
+ safetyCheck();
+ QCOMPARE(callCount, 1);
+
+ callCount = 0;
+ {
+ QSharedPointer<Data> ptr(nullptr, deleter);
+ }
+ safetyCheck();
+ QCOMPARE(callCount, 1);
+
+ callCount = 0;
+ {
+ QSharedPointer<Data> ptr1(null, deleter);
+ QSharedPointer<Data> ptr2(nullptr, deleter);
+ }
+ safetyCheck();
+ QCOMPARE(callCount, 2);
+}
+
void customQObjectDeleterFn(QObject *obj)
{
++customDeleterFnCallCount;
@@ -2044,7 +1986,7 @@ class ThreadData
QAtomicInt * volatile ptr;
public:
ThreadData(QAtomicInt *p) : ptr(p) { }
- ~ThreadData() { ++ptr; }
+ ~ThreadData() { QtPrivate::volatilePreIncrement(ptr); }
void ref()
{
// if we're called after the destructor, we'll crash
@@ -2055,9 +1997,9 @@ public:
class StrongThread: public QThread
{
protected:
- void run()
+ void run() override
{
- usleep(QRandomGenerator::global()->bounded(2000));
+ sleep(std::chrono::microseconds{QRandomGenerator::global()->bounded(2000)});
ptr->ref();
ptr.clear();
}
@@ -2068,9 +2010,9 @@ public:
class WeakThread: public QThread
{
protected:
- void run()
+ void run() override
{
- usleep(QRandomGenerator::global()->bounded(2000));
+ sleep(std::chrono::microseconds{QRandomGenerator::global()->bounded(2000)});
QSharedPointer<ThreadData> ptr = weak;
if (ptr)
ptr->ref();
@@ -2114,7 +2056,7 @@ void tst_QSharedPointer::threadStressTest()
memset(guard2, 0, sizeof guard2);
for (int r = 0; r < 5; ++r) {
- QVector<QThread*> allThreads(6 * qMax(strongThreadCount, weakThreadCount) + 3, 0);
+ QList<QThread*> allThreads(6 * qMax(strongThreadCount, weakThreadCount) + 3, 0);
QSharedPointer<ThreadData> base = QSharedPointer<ThreadData>(new ThreadData(&counter));
counter.storeRelaxed(0);
@@ -2133,11 +2075,11 @@ void tst_QSharedPointer::threadStressTest()
base.clear();
// start threads
- for (int i = 0; i < allThreads.count(); ++i)
+ for (int i = 0; i < allThreads.size(); ++i)
if (allThreads[i]) allThreads[i]->start();
// wait for them to finish
- for (int i = 0; i < allThreads.count(); ++i)
+ for (int i = 0; i < allThreads.size(); ++i)
if (allThreads[i]) allThreads[i]->wait();
qDeleteAll(allThreads);
@@ -2155,7 +2097,7 @@ void tst_QSharedPointer::threadStressTest()
}
}
-template<typename Container, bool Ordered>
+template<typename Container, bool Ordered, bool Multi>
void hashAndMapTest()
{
typedef typename Container::key_type Key;
@@ -2200,26 +2142,30 @@ void hashAndMapTest()
QVERIFY(it == c.end());
}
- c.insertMulti(k1, Value(47));
- it = c.find(k1);
- QVERIFY(it != c.end());
- QCOMPARE(it.key(), k1);
- ++it;
- QVERIFY(it != c.end());
- QCOMPARE(it.key(), k1);
- ++it;
- if (Ordered)
- QVERIFY(it == c.end());
+ if (Multi) {
+ c.insert(k1, Value(47));
+ it = c.find(k1);
+ QVERIFY(it != c.end());
+ QCOMPARE(it.key(), k1);
+ ++it;
+ QVERIFY(it != c.end());
+ QCOMPARE(it.key(), k1);
+ ++it;
+ if (Ordered)
+ QVERIFY(it == c.end());
+ }
}
void tst_QSharedPointer::map()
{
- hashAndMapTest<QMap<QSharedPointer<int>, int>, true>();
+ hashAndMapTest<QMap<QSharedPointer<int>, int>, true, false>();
+ hashAndMapTest<QMultiMap<QSharedPointer<int>, int>, true, true>();
}
void tst_QSharedPointer::hash()
{
- hashAndMapTest<QHash<QSharedPointer<int>, int>, false>();
+ hashAndMapTest<QHash<QSharedPointer<int>, int>, false, false>();
+ hashAndMapTest<QMultiHash<QSharedPointer<int>, int>, false, true>();
}
void tst_QSharedPointer::validConstructs()
@@ -2228,7 +2174,10 @@ void tst_QSharedPointer::validConstructs()
Data *aData = new Data;
QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
ptr1 = ptr1; // valid
+QT_WARNING_POP
QSharedPointer<Data> ptr2(ptr1);
@@ -2240,6 +2189,7 @@ void tst_QSharedPointer::validConstructs()
}
}
+#if 0
typedef bool (QTest::QExternalTest:: * TestFunction)(const QByteArray &body);
Q_DECLARE_METATYPE(TestFunction)
void tst_QSharedPointer::invalidConstructs_data()
@@ -2368,12 +2318,12 @@ void tst_QSharedPointer::invalidConstructs_data()
QTest::newRow("weak-pointer-from-regular-pointer")
<< &QTest::QExternalTest::tryCompileFail
- << "Data *ptr = 0;\n"
+ << "Data *ptr = nullptr;\n"
"QWeakPointer<Data> weakptr(ptr);\n";
QTest::newRow("shared-pointer-implicit-from-uninitialized")
<< &QTest::QExternalTest::tryCompileFail
- << "Data *ptr = 0;\n"
+ << "Data *ptr = nullptr;\n"
"QSharedPointer<Data> weakptr = Qt::Uninitialized;\n";
QTest::newRow("incompatible-custom-deleter1")
@@ -2449,6 +2399,7 @@ void tst_QSharedPointer::invalidConstructs()
QFAIL("Fail");
}
}
+#endif // #if 0
void tst_QSharedPointer::qvariantCast()
{
@@ -2474,52 +2425,6 @@ void tst_QSharedPointer::qvariantCast()
}
// Intentionally does not compile.
// QSharedPointer<int> sop = qSharedPointerFromVariant<int>(v);
-
-#if QT_DEPRECATED_SINCE(5, 0)
- v = QVariant::fromValue(sp.toWeakRef());
-
- {
- QWeakPointer<QObject> other = qWeakPointerFromVariant<QObject>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QIODevice> other = qWeakPointerFromVariant<QIODevice>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QFile> other = qWeakPointerFromVariant<QFile>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QThread> other = qWeakPointerFromVariant<QThread>(v);
- QVERIFY(!other);
- }
-
- // Intentionally does not compile.
-// QWeakPointer<int> sop = qWeakPointerFromVariant<int>(v);
-
- QFile file;
- QWeakPointer<QFile> tracking = &file;
- tracking.data()->setObjectName("A test name");
- v = QVariant::fromValue(tracking);
-
- {
- QWeakPointer<QObject> other = qWeakPointerFromVariant<QObject>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QIODevice> other = qWeakPointerFromVariant<QIODevice>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QFile> other = qWeakPointerFromVariant<QFile>(v);
- QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
- }
- {
- QWeakPointer<QThread> other = qWeakPointerFromVariant<QThread>(v);
- QVERIFY(!other);
- }
-#endif
}
class SomeClass : public QEnableSharedFromThis<SomeClass>
@@ -2824,7 +2729,7 @@ void tst_QSharedPointer::constructorThrow()
int childDestructorCounter = ThrowData::childDestructorCounter;
QSharedPointer<ThrowData> ptr;
- QVERIFY_EXCEPTION_THROWN(ptr = QSharedPointer<ThrowData>::create(), QString);
+ QVERIFY_THROWS_EXCEPTION(QString, ptr = QSharedPointer<ThrowData>::create());
QVERIFY(ptr.isNull());
QCOMPARE(ThrowData::childGenerationCounter, childGeneration + 1);
// destructor should never be called, if a constructor throws
@@ -2866,7 +2771,7 @@ namespace ReentrancyWhileDestructing {
{
QSharedPointer<IB> b;
- virtual QSharedPointer<IB> getB()
+ virtual QSharedPointer<IB> getB() override
{
return b;
}
@@ -2910,12 +2815,12 @@ struct Overloaded
{
return {};
}
- static const Q_CONSTEXPR uint base1Called = sizeof(std::array<int, 1>);
- static const Q_CONSTEXPR uint base2Called = sizeof(std::array<int, 2>);
+ static const constexpr uint base1Called = sizeof(std::array<int, 1>);
+ static const constexpr uint base2Called = sizeof(std::array<int, 2>);
void test()
{
-#define QVERIFY_CALLS(expr, base) Q_STATIC_ASSERT(sizeof(call(expr)) == base##Called)
+#define QVERIFY_CALLS(expr, base) static_assert(sizeof(call(expr)) == base##Called)
QVERIFY_CALLS(SmartPtr<Base1>{}, base1);
QVERIFY_CALLS(SmartPtr<Base2>{}, base2);
QVERIFY_CALLS(SmartPtr<const Base1>{}, base1);
@@ -2937,5 +2842,140 @@ void tst_QSharedPointer::overloads()
weakOverloaded.test();
}
+void tst_QSharedPointer::ownerComparisons()
+{
+ using SP = QSharedPointer<int>;
+ using WP = QWeakPointer<int>;
+
+#define CHECK_EQ(a, b) \
+ do { \
+ QVERIFY(a.owner_equal(b)); \
+ QVERIFY(b.owner_equal(a)); \
+ QVERIFY(!a.owner_before(b)); \
+ QVERIFY(!b.owner_before(a)); \
+ QVERIFY(a.owner_hash() == b.owner_hash()); \
+ } while (false)
+
+#define CHECK_NOT_EQ(a, b) \
+ do { \
+ QVERIFY(!a.owner_equal(b)); \
+ QVERIFY(!b.owner_equal(a)); \
+ QVERIFY(a.owner_before(b) || b.owner_before(a)); \
+ } while (false)
+
+ // null
+ {
+ SP sp1;
+ SP sp2;
+ WP wp1 = sp1;
+ WP wp2;
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_EQ(sp1, sp2);
+ CHECK_EQ(sp1, wp1);
+ CHECK_EQ(sp2, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_EQ(wp1, wp2);
+ CHECK_EQ(wp2, wp2);
+ }
+
+ // same owner
+ {
+ SP sp1 = SP::create(123);
+ SP sp2 = sp1;
+ WP wp1 = sp1;
+ SP wp2 = sp2;
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_EQ(sp1, sp2);
+ CHECK_EQ(sp1, wp1);
+ CHECK_EQ(sp2, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_EQ(wp1, wp2);
+ }
+
+ // owning vs null
+ {
+ SP sp1 = SP::create(123);
+ SP sp2;
+ WP wp1 = sp1;
+ WP wp2 = sp2;
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_NOT_EQ(sp1, sp2);
+ CHECK_EQ(sp1, wp1);
+ CHECK_EQ(sp2, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_NOT_EQ(wp1, wp2);
+ }
+
+ // different owners
+ {
+ SP sp1 = SP::create(123);
+ SP sp2 = SP::create(456);
+ WP wp1 = sp1;
+ WP wp2 = sp2;
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_NOT_EQ(sp1, sp2);
+ CHECK_EQ(sp1, wp1);
+ CHECK_EQ(sp2, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_NOT_EQ(wp1, wp2);
+ }
+
+ // reset vs. null
+ {
+ SP sp1 = SP::create(123);
+ SP sp2;
+ WP wp1 = sp1;
+ WP wp2;
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_NOT_EQ(sp1, sp2);
+ CHECK_EQ(sp1, wp1);
+ CHECK_NOT_EQ(sp1, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_NOT_EQ(wp1, wp2);
+
+ sp1.reset();
+
+ CHECK_EQ(sp1, sp1);
+ CHECK_EQ(sp1, sp2);
+ CHECK_NOT_EQ(sp1, wp1);
+ CHECK_EQ(sp2, wp2);
+ CHECK_EQ(wp1, wp1);
+ CHECK_NOT_EQ(wp1, wp2);
+ }
+
+ // expired weak pointers
+ {
+ WP wp1 = SP::create(123);
+ WP wp2;
+
+ CHECK_EQ(wp1, wp1);
+ CHECK_NOT_EQ(wp1, wp2);
+ }
+
+ {
+ WP wp1 = SP::create(123);
+ WP wp2 = wp1;
+
+ CHECK_EQ(wp1, wp1);
+ CHECK_EQ(wp1, wp2);
+ }
+
+ {
+ WP wp1 = SP::create(123);
+ WP wp2 = SP::create(456);
+
+ CHECK_EQ(wp1, wp1);
+ CHECK_EQ(wp2, wp2);
+ CHECK_NOT_EQ(wp1, wp2);
+ }
+#undef CHECK_EQ
+#undef CHECK_NOT_EQ
+}
+
QTEST_MAIN(tst_QSharedPointer)
#include "tst_qsharedpointer.moc"
diff --git a/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp b/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp
index 24a0cdc9c1..b39eee7d98 100644
--- a/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/wrapper.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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
#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
# undef QT_SHAREDPOINTER_TRACK_POINTERS
diff --git a/tests/auto/corelib/tools/qsharedpointer/wrapper.h b/tests/auto/corelib/tools/qsharedpointer/wrapper.h
index 18cea6e199..3b0bc09fed 100644
--- a/tests/auto/corelib/tools/qsharedpointer/wrapper.h
+++ b/tests/auto/corelib/tools/qsharedpointer/wrapper.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** 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
#ifndef WRAPPER_H
#define WRAPPER_H
diff --git a/tests/auto/corelib/tools/qsize/CMakeLists.txt b/tests/auto/corelib/tools/qsize/CMakeLists.txt
new file mode 100644
index 0000000000..91de696ddd
--- /dev/null
+++ b/tests/auto/corelib/tools/qsize/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qsize Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsize LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qsize
+ SOURCES
+ tst_qsize.cpp
+)
diff --git a/tests/auto/corelib/tools/qsize/qsize.pro b/tests/auto/corelib/tools/qsize/qsize.pro
deleted file mode 100644
index 9462e98e49..0000000000
--- a/tests/auto/corelib/tools/qsize/qsize.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qsize
-QT = core testlib
-SOURCES = tst_qsize.cpp
diff --git a/tests/auto/corelib/tools/qsize/tst_qsize.cpp b/tests/auto/corelib/tools/qsize/tst_qsize.cpp
index 6824bad9c8..c9699c5e76 100644
--- a/tests/auto/corelib/tools/qsize/tst_qsize.cpp
+++ b/tests/auto/corelib/tools/qsize/tst_qsize.cpp
@@ -1,34 +1,33 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QSize>
+#ifdef QVARIANT_H
+# error "This test requires qsize.h to not include qvariant.h"
+#endif
+
+// don't assume <type_traits>
+template <typename T, typename U>
+constexpr inline bool my_is_same_v = false;
+template <typename T>
+constexpr inline bool my_is_same_v<T, T> = true;
+
+#define CHECK(cvref) \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QSize cvref >())), int cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QSize cvref >())), int cvref >)
+
+CHECK(&);
+CHECK(const &);
+CHECK(&&);
+CHECK(const &&);
+
+#undef CHECK
+
+#include <QTest>
#include <qsize.h>
+#include <array>
+
Q_DECLARE_METATYPE(QMargins)
class tst_QSize : public QObject
@@ -47,8 +46,13 @@ private slots:
void grownOrShrunkBy_data();
void grownOrShrunkBy();
+ void toSizeF_data();
+ void toSizeF();
+
void transpose_data();
void transpose();
+
+ void structuredBinding();
};
// Testing get/set functions
@@ -230,6 +234,30 @@ void tst_QSize::grownOrShrunkBy()
QCOMPARE(shrunk.grownBy(margins), input);
}
+void tst_QSize::toSizeF_data()
+{
+ QTest::addColumn<QSize>("input");
+ QTest::addColumn<QSizeF>("result");
+
+ auto row = [](int w, int h) {
+ QTest::addRow("(%d, %d)", w, h) << QSize(w, h) << QSizeF(w, h);
+ };
+ constexpr std::array samples = {-1, 0, 1};
+ for (int w : samples) {
+ for (int h : samples) {
+ row(w, h);
+ }
+ }
+}
+
+void tst_QSize::toSizeF()
+{
+ QFETCH(const QSize, input);
+ QFETCH(const QSizeF, result);
+
+ QCOMPARE(input.toSizeF(), result);
+}
+
void tst_QSize::transpose_data()
{
QTest::addColumn<QSize>("input1");
@@ -250,5 +278,26 @@ void tst_QSize::transpose()
QCOMPARE(input1 , expected);
}
+void tst_QSize::structuredBinding()
+{
+ {
+ QSize size(10, 20);
+ auto [width, height] = size;
+ QCOMPARE(width, 10);
+ QCOMPARE(height, 20);
+ }
+ {
+ QSize size(30, 40);
+ auto &[width, height] = size;
+ QCOMPARE(width, 30);
+ QCOMPARE(height, 40);
+
+ width = 100;
+ height = 200;
+ QCOMPARE(size.width(), 100);
+ QCOMPARE(size.height(), 200);
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QSize)
#include "tst_qsize.moc"
diff --git a/tests/auto/corelib/tools/qsizef/CMakeLists.txt b/tests/auto/corelib/tools/qsizef/CMakeLists.txt
new file mode 100644
index 0000000000..9adaafe2ea
--- /dev/null
+++ b/tests/auto/corelib/tools/qsizef/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qsizef Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qsizef LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qsizef
+ SOURCES
+ tst_qsizef.cpp
+)
diff --git a/tests/auto/corelib/tools/qsizef/qsizef.pro b/tests/auto/corelib/tools/qsizef/qsizef.pro
deleted file mode 100644
index f5ba220b06..0000000000
--- a/tests/auto/corelib/tools/qsizef/qsizef.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qsizef
-QT = core testlib
-SOURCES = tst_qsizef.cpp
diff --git a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
index bbffa74a62..ee33fa13b6 100644
--- a/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
+++ b/tests/auto/corelib/tools/qsizef/tst_qsizef.cpp
@@ -1,32 +1,29 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QSizeF>
+#ifdef QVARIANT_H
+# error "This test requires qsize.h to not include qvariant.h"
+#endif
+
+// don't assume <type_traits>
+template <typename T, typename U>
+constexpr inline bool my_is_same_v = false;
+template <typename T>
+constexpr inline bool my_is_same_v<T, T> = true;
+
+#define CHECK(cvref) \
+ static_assert(my_is_same_v<decltype(get<0>(std::declval<QSizeF cvref >())), qreal cvref >); \
+ static_assert(my_is_same_v<decltype(get<1>(std::declval<QSizeF cvref >())), qreal cvref >)
+
+CHECK(&);
+CHECK(const &);
+CHECK(&&);
+CHECK(const &&);
+
+#undef CHECK
+
+#include <QTest>
#include <qsize.h>
Q_DECLARE_METATYPE(QMarginsF)
@@ -51,6 +48,8 @@ private slots:
void transpose_data();
void transpose();
+
+ void structuredBinding();
};
void tst_QSizeF::isNull_data()
@@ -214,5 +213,26 @@ void tst_QSizeF::transpose() {
QCOMPARE(input1 , expected);
}
+void tst_QSizeF::structuredBinding()
+{
+ {
+ QSizeF size(10.0, 20.0);
+ auto [width, height] = size;
+ QCOMPARE(width, 10.0);
+ QCOMPARE(height, 20.0);
+ }
+ {
+ QSizeF size(30.0, 40.0);
+ auto &[width, height] = size;
+ QCOMPARE(width, 30.0);
+ QCOMPARE(height, 40.0);
+
+ width = 100.0;
+ height = 200.0;
+ QCOMPARE(size.width(), 100.0);
+ QCOMPARE(size.height(), 200.0);
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QSizeF)
#include "tst_qsizef.moc"
diff --git a/tests/auto/corelib/tools/qspan/CMakeLists.txt b/tests/auto/corelib/tools/qspan/CMakeLists.txt
new file mode 100644
index 0000000000..595d19dc43
--- /dev/null
+++ b/tests/auto/corelib/tools/qspan/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qspan LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qspan
+ SOURCES
+ tst_qspan.cpp
+)
diff --git a/tests/auto/corelib/tools/qspan/tst_qspan.cpp b/tests/auto/corelib/tools/qspan/tst_qspan.cpp
new file mode 100644
index 0000000000..91d2ecf739
--- /dev/null
+++ b/tests/auto/corelib/tools/qspan/tst_qspan.cpp
@@ -0,0 +1,450 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QSpan>
+
+#include <QList>
+#include <QTest>
+
+#include <algorithm>
+#include <array>
+#ifdef __cpp_lib_span
+#include <span>
+#endif
+#include <vector>
+
+namespace {
+
+struct NotNothrowMovable {
+ NotNothrowMovable(NotNothrowMovable &&) noexcept(false) {};
+ NotNothrowMovable &operator=(NotNothrowMovable &&) noexcept(false) { return *this; };
+};
+static_assert(!std::is_nothrow_move_constructible_v<NotNothrowMovable>);
+static_assert(!std::is_nothrow_move_assignable_v<NotNothrowMovable>);
+
+} // unnamed namespace
+
+//
+// QSpan is nothrow movable even if the payload type is not:
+//
+static_assert(std::is_nothrow_move_constructible_v<QSpan<NotNothrowMovable>>);
+static_assert(std::is_nothrow_move_constructible_v<QSpan<NotNothrowMovable, 42>>);
+static_assert(std::is_nothrow_move_constructible_v<QSpan<NotNothrowMovable, 0>>);
+
+static_assert(std::is_nothrow_move_assignable_v<QSpan<NotNothrowMovable>>);
+static_assert(std::is_nothrow_move_assignable_v<QSpan<NotNothrowMovable, 42>>);
+static_assert(std::is_nothrow_move_assignable_v<QSpan<NotNothrowMovable, 0>>);
+
+//
+// All QSpans are trivially destructible and trivially copyable:
+//
+static_assert(std::is_trivially_copyable_v<QSpan<NotNothrowMovable>>);
+static_assert(std::is_trivially_copyable_v<QSpan<NotNothrowMovable, 42>>);
+static_assert(std::is_trivially_copyable_v<QSpan<NotNothrowMovable, 0>>);
+
+static_assert(std::is_trivially_destructible_v<QSpan<NotNothrowMovable>>);
+static_assert(std::is_trivially_destructible_v<QSpan<NotNothrowMovable, 42>>);
+static_assert(std::is_trivially_destructible_v<QSpan<NotNothrowMovable, 0>>);
+
+//
+// Fixed-size QSpans implicitly convert to variable-sized ones:
+//
+static_assert(std::is_convertible_v<QSpan<int, 42>, QSpan<int>>);
+static_assert(std::is_convertible_v<QSpan<int, 0>, QSpan<int>>);
+
+#ifdef __cpp_lib_span
+static_assert(std::is_convertible_v<std::span<int, 42>, QSpan<int>>);
+static_assert(std::is_convertible_v<std::span<int, 0>, QSpan<int>>);
+
+#ifdef __cpp_lib_concepts
+// requires enable_borrowed_range
+static_assert(std::is_convertible_v<QSpan<int, 42>, std::span<int>>);
+static_assert(std::is_convertible_v<QSpan<int, 0>, std::span<int>>);
+#endif // __cpp_lib_concepts
+#endif // __cpp_lib_span
+
+//
+// Mutable spans implicitly convert to read-only ones, but not vice versa:
+//
+static_assert(std::is_convertible_v<QSpan<int>, QSpan<const int>>);
+static_assert(std::is_convertible_v<QSpan<int, 42>, QSpan<const int, 42>>);
+static_assert(std::is_convertible_v<QSpan<int, 0>, QSpan<const int, 0>>);
+
+static_assert(!std::is_convertible_v<QSpan<const int>, QSpan<int>>);
+static_assert(!std::is_convertible_v<QSpan<const int, 42>, QSpan<int, 42>>);
+static_assert(!std::is_convertible_v<QSpan<const int, 0>, QSpan<int, 0>>);
+
+#ifdef __cpp_lib_span
+static_assert(std::is_convertible_v<std::span<int>, QSpan<const int>>);
+static_assert(std::is_convertible_v<std::span<int, 42>, QSpan<const int, 42>>);
+static_assert(std::is_convertible_v<std::span<int, 0>, QSpan<const int, 0>>);
+
+static_assert(!std::is_convertible_v<std::span<const int>, QSpan<int>>);
+static_assert(!std::is_convertible_v<std::span<const int, 42>, QSpan<int, 42>>);
+static_assert(!std::is_convertible_v<std::span<const int, 0>, QSpan<int, 0>>);
+
+static_assert(std::is_convertible_v<QSpan<int>, std::span<const int>>);
+// fixed-size std::span constructors are explicit:
+static_assert(!std::is_convertible_v<QSpan<int, 42>, std::span<const int, 42>>);
+static_assert(!std::is_convertible_v<QSpan<int, 0>, std::span<const int, 0>>);
+// observe: is_convertible<From,To>, but is_constuctible<To,From>!
+static_assert(std::is_constructible_v<std::span<const int, 42>, QSpan<int, 42>>);
+static_assert(std::is_constructible_v<std::span<const int, 0>, QSpan<int, 0>>);
+
+static_assert(!std::is_convertible_v<QSpan<const int>, std::span<int>>);
+static_assert(!std::is_convertible_v<QSpan<const int, 42>, std::span<int, 42>>);
+static_assert(!std::is_convertible_v<QSpan<const int, 0>, std::span<int, 0>>);
+#endif // __cpp_lib_span
+
+// Spans don't convert from nonsense:
+static_assert(!std::is_constructible_v<QSpan<const int>, int&&>);
+
+// Span is constructible from initializer_list
+static_assert( std::is_convertible_v<std::initializer_list<int>, QSpan<const int>>);
+static_assert(!std::is_convertible_v<std::initializer_list<int>, QSpan< int>>);
+static_assert(!std::is_constructible_v<QSpan<int>, std::initializer_list<int>>);
+
+static_assert( std::is_convertible_v<std::initializer_list<int>, QSpan<const int, 4>>); // non-standard, but QSpan considers initializer_list a range
+static_assert( std::is_constructible_v<QSpan<const int, 4>, std::initializer_list<int>>);
+static_assert(!std::is_constructible_v<QSpan< int, 4>, std::initializer_list<int>>);
+
+class tst_QSpan : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+
+private Q_SLOTS:
+ void onlyZeroExtentSpansHaveDefaultCtors() const;
+ void zeroExtentSpansMaintainADataPointer() const;
+ void fromArray() const;
+ void fromStdArray() const;
+ void fromStdInitializerList() const;
+ void fromZeroSizeStdArray() const;
+ void fromStdVector() const;
+ void fromQList() const;
+ void fromInitList() const;
+
+private:
+ template <typename T, std::size_t N>
+ void check_nonempty_span(QSpan<T, N>, qsizetype expectedSize) const;
+ template <typename T, std::size_t N>
+ void check_empty_span_incl_subspans(QSpan<T, N>) const;
+ template <typename T, std::size_t N>
+ void check_empty_span(QSpan<T, N>) const;
+ template <typename T, std::size_t N>
+ void check_null_span(QSpan<T, N>) const;
+
+ template <std::size_t ExpectedExtent, typename C>
+ void from_container_impl(C &&c) const;
+ template <typename C>
+ void from_variable_size_container_impl(C &&c) const;
+};
+
+#define RETURN_IF_FAILED() \
+ do { if (QTest::currentTestFailed()) return; } while (false)
+
+void tst_QSpan::onlyZeroExtentSpansHaveDefaultCtors() const
+{
+ static_assert(std::is_nothrow_default_constructible_v<QSpan<int, 0>>);
+ static_assert(std::is_nothrow_default_constructible_v<QSpan<const int, 0>>);
+ static_assert(std::is_nothrow_default_constructible_v<QSpan<int>>);
+ static_assert(std::is_nothrow_default_constructible_v<QSpan<const int, 0>>);
+
+ QSpan<int, 0> si;
+ check_null_span(si);
+ RETURN_IF_FAILED();
+
+ QSpan<const int, 0> sci;
+ check_null_span(sci);
+ RETURN_IF_FAILED();
+
+ QSpan<int> sdi;
+ check_null_span(sdi);
+ RETURN_IF_FAILED();
+
+ QSpan<const int> sdci;
+ check_null_span(sdci);
+ RETURN_IF_FAILED();
+
+ static_assert(!std::is_default_constructible_v<QSpan<int, 1>>);
+ static_assert(!std::is_default_constructible_v<QSpan<const int, 42>>);
+}
+
+void tst_QSpan::zeroExtentSpansMaintainADataPointer() const
+{
+ int i;
+ QSpan<int, 0> si{&i, 0};
+ QCOMPARE(si.data(), &i);
+ check_empty_span_incl_subspans(si);
+ RETURN_IF_FAILED();
+
+ QSpan<const int, 0> sci{&i, 0};
+ QCOMPARE(sci.data(), &i);
+ check_empty_span_incl_subspans(sci);
+ RETURN_IF_FAILED();
+
+ QSpan<int, 0> sdi{&i, 0};
+ QCOMPARE(sdi.data(), &i);
+ check_empty_span_incl_subspans(sdi);
+ RETURN_IF_FAILED();
+
+ QSpan<const int, 0> sdci{&i, 0};
+ QCOMPARE(sdci.data(), &i);
+ check_empty_span_incl_subspans(sdci);
+ RETURN_IF_FAILED();
+}
+
+template <typename T, std::size_t N>
+void tst_QSpan::check_nonempty_span(QSpan<T, N> s, qsizetype expectedSize) const
+{
+ static_assert(N > 0);
+ QCOMPARE_GT(expectedSize, 0); // otherwise, use check_empty_span!
+
+ QVERIFY(!s.empty());
+ QVERIFY(!s.isEmpty());
+
+ QCOMPARE_EQ(s.size(), expectedSize);
+ QCOMPARE_NE(s.data(), nullptr);
+
+ QCOMPARE_NE(s.begin(), s.end());
+ QCOMPARE_NE(s.rbegin(), s.rend());
+ QCOMPARE_NE(s.cbegin(), s.cend());
+ QCOMPARE_NE(s.crbegin(), s.crend());
+
+ QCOMPARE_EQ(s.end() - s.begin(), s.size());
+ QCOMPARE_EQ(s.cend() - s.cbegin(), s.size());
+ QCOMPARE_EQ(s.rend() - s.rbegin(), s.size());
+ QCOMPARE_EQ(s.crend() - s.crbegin(), s.size());
+
+ QCOMPARE_EQ(std::addressof(s.front()), std::addressof(*s.begin()));
+ QCOMPARE_EQ(std::addressof(s.front()), std::addressof(*s.cbegin()));
+ QCOMPARE_EQ(std::addressof(s.front()), std::addressof(s[0]));
+ QCOMPARE_EQ(std::addressof(s.back()), std::addressof(*s.rbegin()));
+ QCOMPARE_EQ(std::addressof(s.back()), std::addressof(*s.crbegin()));
+ QCOMPARE_EQ(std::addressof(s.back()), std::addressof(s[s.size() - 1]));
+
+ // ### more?
+
+ if (expectedSize == 1) {
+ // don't run into Mandates: Offset >= Extent
+ if constexpr (N > 0) { // incl. N == std::dynamic_extent
+ check_empty_span_incl_subspans(s.template subspan<1>());
+ RETURN_IF_FAILED();
+ }
+ check_empty_span_incl_subspans(s.subspan(1));
+ RETURN_IF_FAILED();
+ } else {
+ // don't run into Mandates: Offset >= Extent
+ if constexpr (N > 1) { // incl. N == std::dynamic_extent
+ check_nonempty_span(s.template subspan<1>(), expectedSize - 1);
+ RETURN_IF_FAILED();
+ }
+ check_nonempty_span(s.subspan(1), expectedSize - 1);
+ RETURN_IF_FAILED();
+ }
+}
+
+template <typename T, std::size_t N>
+void tst_QSpan::check_empty_span(QSpan<T, N> s) const
+{
+ QVERIFY(s.empty());
+ QVERIFY(s.isEmpty());
+
+ QCOMPARE_EQ(s.size(), 0);
+
+ QCOMPARE_EQ(s.begin(), s.end());
+ QCOMPARE_EQ(s.cbegin(), s.cend());
+ QCOMPARE_EQ(s.rbegin(), s.rend());
+ QCOMPARE_EQ(s.crbegin(), s.crend());
+}
+
+template <typename T, std::size_t N>
+void tst_QSpan::check_empty_span_incl_subspans(QSpan<T, N> s) const
+{
+ check_empty_span(s);
+ RETURN_IF_FAILED();
+
+ {
+ const auto fi = s.template first<0>();
+ check_empty_span(fi);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(fi.data(), s.data());
+ }
+ {
+ const auto la = s.template last<0>();
+ check_empty_span(la);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(la.data(), s.data());
+ }
+ {
+ const auto ss = s.template subspan<0>();
+ check_empty_span(ss);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(ss.data(), s.data());
+ }
+ {
+ const auto ss = s.template subspan<0, 0>();
+ check_empty_span(ss);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(ss.data(), s.data());
+ }
+
+ {
+ const auto fi = s.first(0);
+ check_empty_span(fi);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(fi.data(), s.data());
+ }
+ {
+ const auto la = s.last(0);
+ check_empty_span(la);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(la.data(), s.data());
+ }
+ {
+ const auto ss = s.subspan(0);
+ check_empty_span(ss);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(ss.data(), s.data());
+ }
+ {
+ const auto ss = s.subspan(0, 0);
+ check_empty_span(ss);
+ RETURN_IF_FAILED();
+ QCOMPARE_EQ(ss.data(), s.data());
+ }
+}
+
+
+template<typename T, std::size_t N>
+void tst_QSpan::check_null_span(QSpan<T, N> s) const
+{
+ QCOMPARE_EQ(s.data(), nullptr);
+ QCOMPARE_EQ(s.begin(), nullptr);
+ QCOMPARE_EQ(s.cbegin(), nullptr);
+ QCOMPARE_EQ(s.end(), nullptr);
+ check_empty_span_incl_subspans(s);
+}
+
+template <std::size_t ExpectedExtent, typename C>
+void tst_QSpan::from_container_impl(C &&c) const
+{
+ const auto c_size = qsizetype(QSpanPrivate::adl_size(c));
+ const auto c_data = QSpanPrivate::adl_data(c);
+
+ using V = std::remove_reference_t<QSpanPrivate::range_reference_t<C>>;
+ {
+ QSpan si = c; // CTAD
+ static_assert(std::is_same_v<decltype(si), QSpan<V, ExpectedExtent>>);
+
+ QCOMPARE_EQ(si.size(), c_size);
+ QCOMPARE_EQ(si.data(), c_data);
+
+ check_nonempty_span(si, c_size);
+ RETURN_IF_FAILED();
+
+ QSpan<const int> sci = c;
+
+ QCOMPARE_EQ(sci.size(), c_size);
+ QCOMPARE_EQ(sci.data(), c_data);
+
+ check_nonempty_span(sci, c_size);
+ RETURN_IF_FAILED();
+ }
+ {
+ QSpan sci = std::as_const(c); // CTAD
+ static_assert(std::is_same_v<decltype(sci), QSpan<const int, ExpectedExtent>>);
+
+ QCOMPARE_EQ(sci.size(), c_size);
+ QCOMPARE_EQ(sci.data(), c_data);
+
+ check_nonempty_span(sci, c_size);
+ RETURN_IF_FAILED();
+ }
+}
+
+template <typename C>
+void tst_QSpan::from_variable_size_container_impl(C &&c) const
+{
+ constexpr auto E = q20::dynamic_extent;
+ from_container_impl<E>(std::forward<C>(c));
+}
+
+void tst_QSpan::fromArray() const
+{
+ int ai[] = {42, 84, 168, 336};
+ from_container_impl<4>(ai);
+}
+
+void tst_QSpan::fromStdArray() const
+{
+ std::array<int, 4> ai = {42, 84, 168, 336};
+ from_container_impl<4>(ai);
+}
+
+void tst_QSpan::fromStdInitializerList() const
+{
+ std::initializer_list<int> il = {42, 84, 168, 336};
+
+ QSpan sci = il; // CTAD
+ // special case: always deduced as <const int>:
+ static_assert(std::is_same_v<decltype(sci), QSpan<const int>>);
+
+ QCOMPARE_EQ(sci.size(), qsizetype(il.size()));
+ QCOMPARE_EQ(sci.data(), il.begin());
+
+ check_nonempty_span(sci, 4);
+ RETURN_IF_FAILED();
+}
+
+void tst_QSpan::fromZeroSizeStdArray() const
+{
+ std::array<int, 0> ai = {};
+ QSpan si = ai; // CTAD
+ static_assert(std::is_same_v<decltype(si), QSpan<int, 0>>);
+ QCOMPARE_EQ(si.data(), ai.data());
+
+ const std::array<int, 0> cai = {};
+ QSpan csi = cai; // CTAD
+ static_assert(std::is_same_v<decltype(csi), QSpan<const int, 0>>);
+ QCOMPARE_EQ(csi.data(), cai.data());
+
+ std::array<const int, 0> aci = {};
+ QSpan sci = aci; // CTAD
+ static_assert(std::is_same_v<decltype(sci), QSpan<const int, 0>>);
+ QCOMPARE_EQ(sci.data(), aci.data());
+
+ std::array<const int, 0> caci = {};
+ QSpan csci = caci; // CTAD
+ static_assert(std::is_same_v<decltype(csci), QSpan<const int, 0>>);
+ QCOMPARE_EQ(csci.data(), caci.data());
+}
+
+void tst_QSpan::fromStdVector() const
+{
+ std::vector<int> vi = {42, 84, 168, 336};
+ from_variable_size_container_impl(vi);
+}
+
+void tst_QSpan::fromQList() const
+{
+ QList<int> li = {42, 84, 168, 336};
+ from_variable_size_container_impl(li);
+}
+
+void tst_QSpan::fromInitList() const
+{
+ from_variable_size_container_impl(std::initializer_list<int>{42, 84, 168, 336});
+
+ auto l1 = [](QSpan<const int>){};
+ l1({1, 2, 3});
+
+ auto l2 = [](QSpan<const int, 3>){};
+ l2({4, 5, 6});
+}
+
+#undef RETURN_IF_FAILED
+
+QTEST_APPLESS_MAIN(tst_QSpan);
+#include "tst_qspan.moc"
diff --git a/tests/auto/corelib/tools/qstl/CMakeLists.txt b/tests/auto/corelib/tools/qstl/CMakeLists.txt
new file mode 100644
index 0000000000..b2f053e6ce
--- /dev/null
+++ b/tests/auto/corelib/tools/qstl/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qstl Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qstl LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qstl
+ SOURCES
+ tst_qstl.cpp
+)
diff --git a/tests/auto/corelib/tools/qstl/qstl.pro b/tests/auto/corelib/tools/qstl/qstl.pro
deleted file mode 100644
index e57e62b828..0000000000
--- a/tests/auto/corelib/tools/qstl/qstl.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qstl
-QT = core testlib
-SOURCES = tst_qstl.cpp
diff --git a/tests/auto/corelib/tools/qstl/tst_qstl.cpp b/tests/auto/corelib/tools/qstl/tst_qstl.cpp
index 6114da55b4..43d40bc128 100644
--- a/tests/auto/corelib/tools/qstl/tst_qstl.cpp
+++ b/tests/auto/corelib/tools/qstl/tst_qstl.cpp
@@ -1,33 +1,8 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-
-#include <QtTest/QtTest>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+
+#include <QTest>
#include <qstring.h>
diff --git a/tests/auto/corelib/tools/qtaggedpointer/.gitignore b/tests/auto/corelib/tools/qtaggedpointer/.gitignore
new file mode 100644
index 0000000000..d027eb73b2
--- /dev/null
+++ b/tests/auto/corelib/tools/qtaggedpointer/.gitignore
@@ -0,0 +1 @@
+tst_qtaggedpointer
diff --git a/tests/auto/corelib/tools/qtaggedpointer/CMakeLists.txt b/tests/auto/corelib/tools/qtaggedpointer/CMakeLists.txt
new file mode 100644
index 0000000000..fb2e5dc922
--- /dev/null
+++ b/tests/auto/corelib/tools/qtaggedpointer/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qtaggedpointer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtaggedpointer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtaggedpointer
+ SOURCES
+ tst_qtaggedpointer.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp b/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp
new file mode 100644
index 0000000000..a1e61fc3a1
--- /dev/null
+++ b/tests/auto/corelib/tools/qtaggedpointer/tst_qtaggedpointer.cpp
@@ -0,0 +1,478 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QtCore/qtaggedpointer.h>
+
+class tst_QTaggedPointer : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void constExpr();
+ void construction();
+ void assignment();
+ void dereferenceOperator();
+ void pointerOperator();
+ void negationOperator();
+ void operatorBool();
+ void comparison();
+ void tag();
+ void objectMember();
+ void customTagType();
+ void taggedLinkedList();
+};
+
+void tst_QTaggedPointer::constExpr()
+{
+ {
+ constexpr QTaggedPointer<int> p;
+ Q_UNUSED(p);
+ }
+ {
+ enum Foo : uint {};
+ constexpr QTaggedPointer<int, Foo> p;
+ Q_UNUSED(p);
+ }
+ {
+ enum Foo : int {};
+ constexpr QTaggedPointer<int, Foo> p;
+ Q_UNUSED(p);
+ }
+ {
+ constexpr QTaggedPointer<int> p = nullptr;
+ Q_UNUSED(p);
+ }
+ {
+ enum Foo : uint {};
+ constexpr QTaggedPointer<int, Foo> p = nullptr;
+ Q_UNUSED(p);
+ }
+ {
+ enum Foo : int {};
+ constexpr QTaggedPointer<int, Foo> p = nullptr;
+ Q_UNUSED(p);
+ }
+}
+
+void tst_QTaggedPointer::construction()
+{
+ {
+ QTaggedPointer<int> p;
+ QCOMPARE(p.data(), nullptr);
+ QVERIFY(!p.tag());
+ }
+ {
+ QTaggedPointer<int> p(nullptr, 0x1);
+ QCOMPARE(p.data(), nullptr);
+ QCOMPARE(p.tag(), quintptr(0x1));
+ }
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ QTaggedPointer<int> p(rawPointer.data());
+ QCOMPARE(p.data(), rawPointer.data());
+ QVERIFY(!p.tag());
+ }
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ QCOMPARE(p.data(), rawPointer.data());
+ QCOMPARE(p.tag(), quintptr(0x1));
+ }
+}
+
+void tst_QTaggedPointer::assignment()
+{
+ QScopedPointer<int> rawPointer(new int(5));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ QTaggedPointer<int> p2(rawPointer.data(), 0x2);
+
+ QCOMPARE(p.data(), rawPointer.data());
+ QCOMPARE(p.tag(), quintptr(0x1));
+
+ QCOMPARE(p2.data(), rawPointer.data());
+ QCOMPARE(p2.tag(), quintptr(0x2));
+
+ p = nullptr;
+ QCOMPARE(p.data(), nullptr);
+ QCOMPARE(p.tag(), quintptr(0x1));
+
+ p = rawPointer.data();
+ QCOMPARE(p.data(), rawPointer.data());
+ QCOMPARE(p.tag(), quintptr(0x1));
+
+ p = {};
+ QCOMPARE(p.data(), nullptr);
+ QCOMPARE(p.tag(), quintptr(0x0));
+
+ p = p2;
+ QCOMPARE(p.data(), rawPointer.data());
+ QCOMPARE(p.tag(), quintptr(0x2));
+
+ p = nullptr;
+ QCOMPARE(p.data(), nullptr);
+ QCOMPARE(p.tag(), quintptr(0x2));
+
+ p = {};
+ QCOMPARE(p.data(), nullptr);
+ QCOMPARE(p.tag(), quintptr(0x0));
+
+ p = rawPointer.data();
+ QCOMPARE(p.data(), rawPointer.data());
+ QCOMPARE(p.tag(), quintptr(0x0));
+}
+
+class AbstractClass
+{
+public:
+ virtual ~AbstractClass() {}
+ virtual int member() const = 0;
+};
+
+class SubClass : public AbstractClass
+{
+public:
+ int member() const override { return 5; }
+};
+
+void tst_QTaggedPointer::dereferenceOperator()
+{
+ /* Dereference a basic value. */
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ QTaggedPointer<int> p(rawPointer.data());
+ const int value = *p;
+ QCOMPARE(value, 5);
+ }
+
+ /* Dereference a basic value with tag. */
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ const int value = *p;
+ QCOMPARE(value, 5);
+ }
+
+ /* Dereference a pointer to an abstract class. This verifies
+ * that the operator returns a reference, when compiling
+ * with MSVC 2005. */
+ {
+ QScopedPointer<SubClass> ptr(new SubClass());
+ QTaggedPointer<AbstractClass> p(ptr.data());
+ QCOMPARE((*p).member(), 5);
+ }
+
+ /* The operator should be const. */
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ const QTaggedPointer<int> p(rawPointer.data());
+ *p;
+ }
+
+ /* A reference should be returned, not a value. */
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ const QTaggedPointer<int> p(rawPointer.data());
+ Q_UNUSED(static_cast<int &>(*p));
+ }
+
+ /* Instantiated on a const object, the returned object is a const reference. */
+ {
+ QScopedPointer<int> rawPointer(new int(5));
+ const QTaggedPointer<const int> p(rawPointer.data());
+ Q_UNUSED(static_cast<const int &>(*p));
+ }
+}
+
+class Value
+{
+public:
+ int value;
+};
+
+void tst_QTaggedPointer::pointerOperator()
+{
+ {
+ QScopedPointer<Value> valuePtr(new Value{5});
+ QTaggedPointer<Value> p(valuePtr.data());
+ QCOMPARE(p->value, 5);
+ }
+
+ {
+ QScopedPointer<Value> valuePtr(new Value{5});
+ QTaggedPointer<Value> p(valuePtr.data(), 0x1);
+ QCOMPARE(p->value, 5);
+ }
+
+ /* The operator should be const. */
+ {
+ QScopedPointer<Value> valuePtr(new Value{5});
+ const QTaggedPointer<Value> p(valuePtr.data());
+ QVERIFY(p->value);
+ }
+}
+
+void tst_QTaggedPointer::negationOperator()
+{
+ /* Invoke on default constructed value. */
+ {
+ QTaggedPointer<int> p;
+ QVERIFY(!p);
+ }
+
+ /* Invoke on nullptr value with tag. */
+ {
+ QTaggedPointer<int> p(nullptr, 0x1);
+ QVERIFY(!p);
+ }
+
+ /* Invoke on a value. */
+ {
+ QScopedPointer<int> rawPointer(new int(2));
+ QTaggedPointer<int> p(rawPointer.data());
+ QCOMPARE(!p, false);
+ }
+
+ /* Invoke on a value with tag. */
+ {
+ QScopedPointer<int> rawPointer(new int(2));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ QCOMPARE(!p, false);
+ }
+
+ /* The signature should be const. */
+ {
+ const QTaggedPointer<int> p;
+ !p;
+ }
+
+ /* The return value should be bool. */
+ {
+ const QTaggedPointer<int> p;
+ Q_UNUSED(static_cast<bool>(!p));
+ }
+}
+
+void tst_QTaggedPointer::operatorBool()
+{
+ /* Invoke on default constructed value. */
+ {
+ QTaggedPointer<int> p;
+ QCOMPARE(bool(p), false);
+ }
+
+ /* Invoke on nullptr value with tag. */
+ {
+ QTaggedPointer<int> p(nullptr, 0x1);
+ QCOMPARE(bool(p), false);
+ }
+
+ /* Invoke on active value. */
+ {
+ QScopedPointer<int> rawPointer(new int(3));
+ QTaggedPointer<int> p(rawPointer.data());
+ QVERIFY(p);
+ }
+
+ /* Invoke on active value with tag. */
+ {
+ QScopedPointer<int> rawPointer(new int(3));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ QVERIFY(p);
+ }
+
+ /* The signature should be const and return bool. */
+ {
+ const QTaggedPointer<int> p;
+ (void)static_cast<bool>(p);
+ }
+}
+
+template <class A1, class A2, class B>
+void comparisonTest(const A1 &a1, const A2 &a2, const B &b)
+{
+ // test equality on equal pointers
+ QVERIFY(a1 == a2);
+ QVERIFY(a2 == a1);
+
+ // test inequality on equal pointers
+ QVERIFY(!(a1 != a2));
+ QVERIFY(!(a2 != a1));
+
+ // test equality on unequal pointers
+ QVERIFY(!(a1 == b));
+ QVERIFY(!(a2 == b));
+ QVERIFY(!(b == a1));
+ QVERIFY(!(b == a2));
+
+ // test inequality on unequal pointers
+ QVERIFY(b != a1);
+ QVERIFY(b != a2);
+ QVERIFY(a1 != b);
+ QVERIFY(a2 != b);
+}
+
+void tst_QTaggedPointer::comparison()
+{
+ QScopedPointer<int> a(new int(5));
+
+ {
+ QTaggedPointer<int> a1(a.data());
+ QTaggedPointer<int> a2(a.data());
+ QScopedPointer<int> rawPointer(new int(6));
+ QTaggedPointer<int> b(rawPointer.data());
+
+ comparisonTest(a1, a1, b);
+ comparisonTest(a2, a2, b);
+ comparisonTest(a1, a2, b);
+ }
+ {
+ QTaggedPointer<int> a1(a.data(), 0x1);
+ QTaggedPointer<int> a2(a.data(), 0x1);
+ QScopedPointer<int> rawPointer(new int(6));
+ QTaggedPointer<int> b(rawPointer.data(), 0x1);
+
+ comparisonTest(a1, a1, b);
+ comparisonTest(a2, a2, b);
+ comparisonTest(a1, a2, b);
+ }
+ {
+ QTaggedPointer<int> a1(a.data(), 0x1);
+ QTaggedPointer<int> a2(a.data(), 0x2);
+ QScopedPointer<int> rawPointer(new int(6));
+ QTaggedPointer<int> b(rawPointer.data(), 0x2);
+
+ comparisonTest(a1, a1, b);
+ comparisonTest(a2, a2, b);
+ comparisonTest(a1, a2, b);
+ }
+ {
+ QTaggedPointer<int> p;
+ QVERIFY(p.isNull());
+ QVERIFY(p == nullptr);
+ QVERIFY(nullptr == p);
+ }
+ {
+ QTaggedPointer<int> p(nullptr, 0x1);
+ QVERIFY(p.isNull());
+ QVERIFY(p == nullptr);
+ QVERIFY(nullptr == p);
+ }
+ {
+ QScopedPointer<int> rawPointer(new int(42));
+ QTaggedPointer<int> p(rawPointer.data());
+ QVERIFY(!p.isNull());
+ QVERIFY(p != nullptr);
+ QVERIFY(nullptr != p);
+ }
+ {
+ QScopedPointer<int> rawPointer(new int(42));
+ QTaggedPointer<int> p(rawPointer.data(), 0x1);
+ QVERIFY(!p.isNull());
+ QVERIFY(p != nullptr);
+ QVERIFY(nullptr != p);
+ }
+}
+
+void tst_QTaggedPointer::tag()
+{
+ QScopedPointer<int> rawPointer(new int(3));
+ QTaggedPointer<int> p(rawPointer.data());
+ QCOMPARE(*p.data(), 3);
+ QVERIFY(!p.tag());
+
+ p.setTag(0x1);
+ QCOMPARE(p.tag(), 0x1);
+
+ p.setTag(0x2);
+ QCOMPARE(p.tag(), 0x2);
+}
+
+struct Foo
+{
+ Foo() : p(nullptr) {}
+ Foo(const Foo &other) : p(other.p) {}
+ Foo &operator=(const Foo &other) {
+ p = other.p;
+ return *this;
+ }
+ QTaggedPointer<int> p;
+};
+
+void tst_QTaggedPointer::objectMember()
+{
+ QScopedPointer<int> rawPointer(new int(42));
+ Foo f;
+ f.p = QTaggedPointer<int>(rawPointer.data(), 0x1);
+
+ Foo f2(f);
+ QCOMPARE(f2.p.data(), f.p.data());
+ QCOMPARE(f2.p.tag(), f.p.tag());
+
+ Foo f3 = f;
+ QCOMPARE(f3.p.data(), f.p.data());
+ QCOMPARE(f3.p.tag(), f.p.tag());
+}
+
+class Bar
+{
+ Q_GADGET
+public:
+ enum Tag {
+ NoTag = 0,
+ FirstTag = 1,
+ SecondTag = 2
+ };
+ Q_DECLARE_FLAGS(Tags, Tag)
+ Q_FLAG(Tags)
+
+ int value;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Bar::Tags)
+
+void tst_QTaggedPointer::customTagType()
+{
+ QScopedPointer<Bar> barPtr(new Bar{5});
+ typedef QTaggedPointer<Bar, Bar::Tags> TaggedBar;
+ TaggedBar p(barPtr.data());
+ QCOMPARE(p->value, 5);
+ QVERIFY(TaggedBar::maximumTag());
+
+ QVERIFY(!p.tag());
+ QCOMPARE(p.tag(), Bar::NoTag);
+
+ p.setTag(Bar::FirstTag | Bar::SecondTag);
+ QCOMPARE(p->value, 5);
+ QCOMPARE(p.tag(), Bar::FirstTag | Bar::SecondTag);
+}
+
+// Compile-only test to ensure it's possible to use tagged pointers
+// with incomplete types.
+struct LinkedListItem
+{
+ enum Tag {
+ NoTag = 0,
+ FirstTag = 1
+ };
+ Q_DECLARE_FLAGS(Tags, Tag)
+
+ QTaggedPointer<LinkedListItem, Tag> next;
+
+ ~LinkedListItem()
+ {
+ delete next.data();
+ }
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(LinkedListItem::Tags)
+
+void tst_QTaggedPointer::taggedLinkedList()
+{
+ QScopedPointer<LinkedListItem> lli(new LinkedListItem);
+ lli->next = QTaggedPointer<LinkedListItem, LinkedListItem::Tag>(new LinkedListItem);
+ lli->next.setTag(LinkedListItem::FirstTag);
+}
+
+QTEST_MAIN(tst_QTaggedPointer)
+#include "tst_qtaggedpointer.moc"
diff --git a/tests/auto/corelib/tools/qtimeline/BLACKLIST b/tests/auto/corelib/tools/qtimeline/BLACKLIST
index 9794b0059f..8040a529ba 100644
--- a/tests/auto/corelib/tools/qtimeline/BLACKLIST
+++ b/tests/auto/corelib/tools/qtimeline/BLACKLIST
@@ -1,7 +1,6 @@
[interpolation]
-windows-10 msvc-2015
+windows
osx
[frameRate]
-osx-10.12
-osx-10.13
+macos
diff --git a/tests/auto/corelib/tools/qtimeline/CMakeLists.txt b/tests/auto/corelib/tools/qtimeline/CMakeLists.txt
new file mode 100644
index 0000000000..a43e93990a
--- /dev/null
+++ b/tests/auto/corelib/tools/qtimeline/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qtimeline Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtimeline LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtimeline
+ SOURCES
+ tst_qtimeline.cpp
+ LIBRARIES
+ Qt::TestPrivate
+)
diff --git a/tests/auto/corelib/tools/qtimeline/qtimeline.pro b/tests/auto/corelib/tools/qtimeline/qtimeline.pro
deleted file mode 100644
index 9424cf8fd2..0000000000
--- a/tests/auto/corelib/tools/qtimeline/qtimeline.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qtimeline
-QT = core testlib
-SOURCES = tst_qtimeline.cpp
diff --git a/tests/auto/corelib/tools/qtimeline/tst_qtimeline.cpp b/tests/auto/corelib/tools/qtimeline/tst_qtimeline.cpp
index b68c582732..3593a65c4e 100644
--- a/tests/auto/corelib/tools/qtimeline/tst_qtimeline.cpp
+++ b/tests/auto/corelib/tools/qtimeline/tst_qtimeline.cpp
@@ -1,32 +1,9 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QtTest/private/qpropertytesthelper_p.h>
+#include <QSignalSpy>
#include <qtimeline.h>
@@ -36,15 +13,20 @@ class tst_QTimeLine : public QObject
private slots:
void range();
void currentTime();
+ void bindableCurrentTime();
void duration();
+ void bindableDuration();
void frameRate();
+ void bindableUpdateInterval();
void value();
void currentFrame();
void loopCount();
+ void bindableLoopCount();
void interpolation();
void reverse_data();
void reverse();
void toggleDirection();
+ void bindableDirection();
void frameChanged();
void stopped();
void finished();
@@ -57,6 +39,7 @@ private slots:
void resume();
void restart();
void setPaused();
+ void automatedBindableTests();
protected slots:
void finishedSlot();
@@ -97,7 +80,7 @@ void tst_QTimeLine::range()
timeLine.setStartFrame(5000);
QVERIFY(timeLine.currentFrame() > oldValue);
timeLine.setFrameRange(0, 500);
- QTRY_VERIFY(spy.count() > 1);
+ QTRY_VERIFY(spy.size() > 1);
QVERIFY(timeLine.currentFrame() < oldValue);
}
@@ -119,7 +102,7 @@ void tst_QTimeLine::currentTime()
spy.clear();
timeLine.setCurrentTime(timeLine.duration()/2);
timeLine.setCurrentTime(timeLine.duration()/2);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
spy.clear();
QCOMPARE(timeLine.currentTime(), timeLine.duration()/2);
timeLine.resume();
@@ -143,6 +126,55 @@ void tst_QTimeLine::currentTime()
timeLine.stop();
}
+void tst_QTimeLine::bindableCurrentTime()
+{
+ QTimeLine timeLine(2000);
+ QProperty<int> currentTimeObserver([&]() { return timeLine.currentTime(); });
+
+ timeLine.setUpdateInterval((timeLine.duration() / 2) / 33);
+ timeLine.setFrameRange(10, 20);
+ QCOMPARE(timeLine.currentTime(), 0);
+ QCOMPARE(currentTimeObserver.value(), 0);
+ QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
+
+ timeLine.start();
+ QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
+ QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
+ QTRY_VERIFY(timeLine.currentTime() > timeLine.duration() / 2 - timeLine.duration() / 4);
+ QVERIFY(timeLine.currentTime() < timeLine.duration() / 2 + timeLine.duration() / 4);
+ QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
+
+ QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
+ QCOMPARE(timeLine.currentTime(), timeLine.duration());
+ QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
+
+ QSignalSpy spy(&timeLine, &QTimeLine::valueChanged);
+ QVERIFY(spy.isValid());
+ spy.clear();
+ QProperty<int> referenceCurrentTime(timeLine.duration() / 2);
+ timeLine.bindableCurrentTime().setBinding([&]() { return referenceCurrentTime.value(); });
+ QCOMPARE(spy.size(), 1);
+ // setting it a second time to check that valueChanged() is emitted only once
+ referenceCurrentTime = timeLine.duration() / 2;
+ QCOMPARE(spy.size(), 1);
+
+ spy.clear();
+ QCOMPARE(timeLine.currentTime(), timeLine.duration() / 2);
+ QCOMPARE(currentTimeObserver.value(), timeLine.duration() / 2);
+ timeLine.resume();
+ // Let it update on its own
+ QCOMPARE(timeLine.state(), QTimeLine::Running);
+ QTRY_VERIFY(currentTimeObserver.value() > timeLine.duration() / 2);
+ QVERIFY(currentTimeObserver.value() < timeLine.duration());
+ QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
+ QCOMPARE(currentTimeObserver.value(), timeLine.duration());
+ // the resume above should have broken the connection to referenceCurrentTime, check that:
+ spy.clear();
+ referenceCurrentTime = 0;
+ QCOMPARE(currentTimeObserver.value(), timeLine.duration());
+ QCOMPARE(spy.size(), 0);
+}
+
void tst_QTimeLine::duration()
{
QTimeLine timeLine(200);
@@ -160,6 +192,35 @@ void tst_QTimeLine::duration()
QCOMPARE(timeLine.duration(), 1000);
}
+void tst_QTimeLine::bindableDuration()
+{
+ QTimeLine timeLine(200);
+ QProperty<int> durationObserver;
+ durationObserver.setBinding([&]() { return timeLine.duration(); });
+ QCOMPARE(durationObserver.value(), timeLine.duration());
+
+ timeLine.setFrameRange(10, 20);
+ QCOMPARE(timeLine.duration(), 200);
+
+ QProperty<int> referenceDuration(500);
+ timeLine.bindableDuration().setBinding([&]() { return referenceDuration.value(); });
+ QCOMPARE(durationObserver.value(), referenceDuration.value());
+
+ QCOMPARE(timeLine.duration(), 500);
+
+ timeLine.start();
+ QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
+ QTRY_VERIFY(timeLine.currentTime() > 0);
+ QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
+ QCOMPARE(timeLine.currentTime(), 500);
+ // The duration shouldn't change
+ QCOMPARE(timeLine.duration(), 500);
+
+ referenceDuration = 30;
+ QCOMPARE(timeLine.duration(), 30);
+ QCOMPARE(durationObserver.value(), 30);
+}
+
void tst_QTimeLine::frameRate()
{
QTimeLine timeLine;
@@ -175,7 +236,7 @@ void tst_QTimeLine::frameRate()
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
- int slowCount = spy.count();
+ int slowCount = spy.size();
// Faster!!
timeLine.setUpdateInterval(1000 / 100);
@@ -184,7 +245,41 @@ void tst_QTimeLine::frameRate()
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
- QVERIFY2(slowCount < spy.count(), QByteArray::number(spy.count()));
+ QVERIFY2(slowCount < spy.size(), QByteArray::number(spy.size()));
+}
+
+void tst_QTimeLine::bindableUpdateInterval()
+{
+ QTimeLine timeLine;
+ timeLine.setFrameRange(100, 2000);
+
+ QProperty<int> updateIntervalObserver;
+ updateIntervalObserver.setBinding([&]() { return timeLine.updateInterval(); });
+
+ QCOMPARE(updateIntervalObserver.value(), 1000 / 25);
+ QProperty<int> updateIntervalReference(1000 / 60);
+ timeLine.bindableUpdateInterval().setBinding([&]() { return updateIntervalReference.value(); });
+
+ updateIntervalReference = 1000 / 60;
+ QCOMPARE(updateIntervalObserver.value(), 1000 / 60);
+
+ // Default speed
+ updateIntervalReference = 1000 / 33;
+ QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
+ QVERIFY(spy.isValid());
+ timeLine.start();
+ QTest::qWait(timeLine.duration() * 2);
+ QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
+ int slowCount = spy.size();
+
+ // Faster!!
+ updateIntervalReference = 1000 / 100;
+ spy.clear();
+ timeLine.setCurrentTime(0);
+ timeLine.start();
+ QTest::qWait(timeLine.duration() * 2);
+ QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
+ QVERIFY2(slowCount < spy.size(), QByteArray::number(spy.size()));
}
void tst_QTimeLine::value()
@@ -199,7 +294,7 @@ void tst_QTimeLine::value()
QTRY_VERIFY(timeLine.currentValue() > 0);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentValue(), 1.0);
- QVERIFY(spy.count() > 0);
+ QVERIFY(spy.size() > 0);
// Reverse should decrease the value
timeLine.setCurrentTime(100);
@@ -248,7 +343,7 @@ void tst_QTimeLine::loopCount()
timeLine.setLoopCount(0);
QCOMPARE(timeLine.loopCount(), 0);
- // Default speed infiniti looping
+ // Default speed endless looping
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
@@ -263,7 +358,7 @@ void tst_QTimeLine::loopCount()
QCOMPARE(timeLine.state(), QTimeLine::Running);
timeLine.stop();
- timeLine.setDuration(2500); // ### some platforms have a very low resolution timer
+ timeLine.setDuration(2500); // some platforms have a very low resolution timer
timeLine.setFrameRange(0, 2);
timeLine.setLoopCount(4);
@@ -278,41 +373,125 @@ void tst_QTimeLine::loopCount()
for(int i=0;i<2;i++) {
timeLine.start();
- //we clear te list after the start so we don't catch
- //a frameChanged signal for the frame 0 at the beginning
+ // we clear the list after the start so we don't catch
+ // a frameChanged signal for the frame 0 at the beginning
finishedSpy.clear();
frameChangedSpy.clear();
loop.exec();
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(frameChangedSpy.count(), 11);
- for (int i = 0; i < 11; ++i) {
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(frameChangedSpy.size(), 11);
+ for (int i = 0; i < 11; ++i)
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), (i+1) % 3);
- }
}
timeLine.setDirection(QTimeLine::Backward);
timeLine.start();
loop.exec();
- QCOMPARE(finishedSpy.count(), 2);
- QCOMPARE(frameChangedSpy.count(), 22);
+ QCOMPARE(finishedSpy.size(), 2);
+ QCOMPARE(frameChangedSpy.size(), 22);
for (int i = 11; i < 22; ++i) {
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), 2 - (i+2) % 3);
}
}
+void tst_QTimeLine::bindableLoopCount()
+{
+ QTimeLine timeLine(200);
+ QProperty<int> referenceLoopCount(1);
+ timeLine.bindableLoopCount().setBinding([&]() { return referenceLoopCount.value(); });
+ QProperty<int> loopCountObserver([&]() { return timeLine.loopCount(); });
+
+ QCOMPARE(referenceLoopCount.value(), 1);
+ QCOMPARE(timeLine.loopCount(), 1);
+ QCOMPARE(loopCountObserver.value(), 1);
+
+ timeLine.setFrameRange(10, 20);
+
+ QCOMPARE(referenceLoopCount.value(), 1);
+ QCOMPARE(timeLine.loopCount(), 1);
+ QCOMPARE(loopCountObserver.value(), 1);
+
+ referenceLoopCount = 0;
+
+ QCOMPARE(referenceLoopCount.value(), 0);
+ QCOMPARE(timeLine.loopCount(), 0);
+ QCOMPARE(loopCountObserver.value(), 0);
+
+ // Default speed endless looping
+ QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
+ QVERIFY(spy.isValid());
+ timeLine.start();
+ QTest::qWait(timeLine.duration());
+ QCOMPARE(timeLine.state(), QTimeLine::Running);
+ // QCOMPARE(timeLine.currentFrame(), 20);
+ QTest::qWait(timeLine.duration() * 6);
+ QCOMPARE(timeLine.state(), QTimeLine::Running);
+ QVERIFY(timeLine.currentTime() >= 0);
+ QVERIFY(timeLine.currentFrame() >= 10);
+ QVERIFY(timeLine.currentFrame() <= 20);
+ QCOMPARE(timeLine.state(), QTimeLine::Running);
+ timeLine.stop();
+
+ timeLine.setDuration(2500); // some platforms have a very low resolution timer
+ timeLine.setFrameRange(0, 2);
+ referenceLoopCount = 4;
+
+ QSignalSpy finishedSpy(&timeLine, &QTimeLine::finished);
+ QSignalSpy frameChangedSpy(&timeLine, &QTimeLine::frameChanged);
+ QVERIFY(finishedSpy.isValid());
+ QVERIFY(frameChangedSpy.isValid());
+ QEventLoop loop;
+ connect(&timeLine, SIGNAL(finished()), &loop, SLOT(quit()));
+
+ for (int i = 0; i < 2; i++) {
+
+ timeLine.start();
+ // we clear the list after the start so we don't catch
+ // a frameChanged signal for the frame 0 at the beginning
+ finishedSpy.clear();
+ frameChangedSpy.clear();
+
+ loop.exec();
+
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(frameChangedSpy.size(), 11);
+ for (int i = 0; i < 11; ++i)
+ QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), (i + 1) % 3);
+ }
+
+ timeLine.setDirection(QTimeLine::Backward);
+ timeLine.start();
+ loop.exec();
+
+ QCOMPARE(finishedSpy.size(), 2);
+ QCOMPARE(frameChangedSpy.size(), 22);
+ for (int i = 11; i < 22; ++i)
+ QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), 2 - (i + 2) % 3);
+}
+
void tst_QTimeLine::interpolation()
{
+ // also tests bindableEasingCurve
QTimeLine timeLine(400);
- QCOMPARE(timeLine.curveShape(), QTimeLine::EaseInOutCurve);
+ QProperty<QEasingCurve> easingCurveObserver([&]() { return timeLine.easingCurve(); });
+
+ QCOMPARE(timeLine.easingCurve(), QEasingCurve::InOutSine);
+ QCOMPARE(easingCurveObserver.value(), QEasingCurve::InOutSine);
+
timeLine.setFrameRange(100, 200);
- timeLine.setCurveShape(QTimeLine::LinearCurve);
- QCOMPARE(timeLine.curveShape(), QTimeLine::LinearCurve);
+ QProperty<QEasingCurve> referenceEasingCurve(QEasingCurve::Linear);
+ timeLine.bindableEasingCurve().setBinding([&]() { return referenceEasingCurve.value(); });
+ QCOMPARE(timeLine.easingCurve(), QEasingCurve::Linear);
+ QCOMPARE(easingCurveObserver.value(), QEasingCurve::Linear);
// smooth
- timeLine.setCurveShape(QTimeLine::EaseInOutCurve);
+ referenceEasingCurve = QEasingCurve::InOutSine;
+ QCOMPARE(timeLine.easingCurve(), QEasingCurve::InOutSine);
+ QCOMPARE(easingCurveObserver.value(), QEasingCurve::InOutSine);
+
timeLine.start();
QTest::qWait(100);
QCOMPARE(timeLine.state(), QTimeLine::Running);
@@ -323,7 +502,11 @@ void tst_QTimeLine::interpolation()
timeLine.setCurrentTime(0);
// linear
- timeLine.setCurveShape(QTimeLine::LinearCurve);
+ referenceEasingCurve = QEasingCurve::Linear;
+
+ QCOMPARE(timeLine.easingCurve(), QEasingCurve::Linear);
+ QCOMPARE(easingCurveObserver.value(), QEasingCurve::Linear);
+
timeLine.start();
QTest::qWait(100);
QCOMPARE(timeLine.state(), QTimeLine::Running);
@@ -373,7 +556,7 @@ void tst_QTimeLine::reverse()
QFETCH(int, wait2);
QTimeLine timeLine(duration);
- timeLine.setCurveShape(QTimeLine::LinearCurve);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setFrameRange(start, end);
timeLine.setDirection((QTimeLine::Direction)direction);
@@ -406,20 +589,44 @@ void tst_QTimeLine::reverse()
void tst_QTimeLine::toggleDirection()
{
- // Note: enum values are cast to int so that QCOMPARE will show
- // the values if they don't match.
QTimeLine timeLine;
- QCOMPARE(int(timeLine.direction()), int(QTimeLine::Forward));
+ QCOMPARE(timeLine.direction(), QTimeLine::Forward);
timeLine.toggleDirection();
- QCOMPARE(int(timeLine.direction()), int(QTimeLine::Backward));
+ QCOMPARE(timeLine.direction(), QTimeLine::Backward);
timeLine.toggleDirection();
- QCOMPARE(int(timeLine.direction()), int(QTimeLine::Forward));
+ QCOMPARE(timeLine.direction(), QTimeLine::Forward);
+}
+
+void tst_QTimeLine::bindableDirection()
+{
+ // Note: enum values are cast to int so that QCOMPARE will show
+ // the values if they don't match.
+ QTimeLine timeLine;
+ QProperty<QTimeLine::Direction> directionObserver([&]() { return timeLine.direction(); });
+ QProperty<QTimeLine::Direction> referenceDirection(QTimeLine::Forward);
+ timeLine.bindableDirection().setBinding([&]() { return referenceDirection.value(); });
+
+ QCOMPARE(referenceDirection.value(), QTimeLine::Forward);
+ QCOMPARE(timeLine.direction(), QTimeLine::Forward);
+ QCOMPARE(directionObserver.value(), QTimeLine::Forward);
+
+ referenceDirection = QTimeLine::Backward;
+
+ QCOMPARE(referenceDirection.value(), QTimeLine::Backward);
+ QCOMPARE(timeLine.direction(), QTimeLine::Backward);
+ QCOMPARE(directionObserver.value(), QTimeLine::Backward);
+
+ referenceDirection = QTimeLine::Forward;
+
+ QCOMPARE(referenceDirection.value(), QTimeLine::Forward);
+ QCOMPARE(timeLine.direction(), QTimeLine::Forward);
+ QCOMPARE(directionObserver.value(), QTimeLine::Forward);
}
void tst_QTimeLine::frameChanged()
{
QTimeLine timeLine;
- timeLine.setCurveShape(QTimeLine::LinearCurve);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setFrameRange(0,9);
timeLine.setUpdateInterval(800);
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
@@ -429,14 +636,14 @@ void tst_QTimeLine::frameChanged()
timeLine.start();
QTest::qWait(timeLine.duration()/2);
QCOMPARE(timeLine.state(), QTimeLine::Running);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
QTest::qWait(timeLine.duration());
if (timeLine.state() != QTimeLine::NotRunning)
QEXPECT_FAIL("", "QTBUG-24796: QTimeLine runs slower than it should", Abort);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
- if (spy.count() != 1)
+ if (spy.size() != 1)
QEXPECT_FAIL("", "QTBUG-24796: QTimeLine runs slower than it should", Abort);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// Test what happens when the frames are all emitted well before duration expires.
timeLine.setUpdateInterval(5);
@@ -445,7 +652,7 @@ void tst_QTimeLine::frameChanged()
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
- QCOMPARE(spy.count(), 10);
+ QCOMPARE(spy.size(), 10);
}
void tst_QTimeLine::stopped()
@@ -458,11 +665,11 @@ void tst_QTimeLine::stopped()
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
spy.clear();
timeLine.start();
timeLine.stop();
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
timeLine.setDirection(QTimeLine::Backward);
QCOMPARE(timeLine.loopCount(), 1);
}
@@ -474,13 +681,13 @@ void tst_QTimeLine::finished()
QSignalSpy spy(&timeLine, &QTimeLine::finished);
QVERIFY(spy.isValid());
timeLine.start();
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
spy.clear();
timeLine.start();
timeLine.stop();
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
void tst_QTimeLine::isRunning()
@@ -513,13 +720,13 @@ void tst_QTimeLine::multipleTimeLines()
timeLine.start();
timeLineKiller.stop();
QTest::qWait(timeLine.duration()*2);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_QTimeLine::sineCurve()
{
QTimeLine timeLine(1000);
- timeLine.setCurveShape(QTimeLine::SineCurve);
+ timeLine.setEasingCurve(QEasingCurve::SineCurve);
QCOMPARE(timeLine.valueForTime(0), qreal(0));
QCOMPARE(timeLine.valueForTime(250), qreal(0.5));
QCOMPARE(timeLine.valueForTime(500), qreal(1));
@@ -530,7 +737,7 @@ void tst_QTimeLine::sineCurve()
void tst_QTimeLine::cosineCurve()
{
QTimeLine timeLine(1000);
- timeLine.setCurveShape(QTimeLine::CosineCurve);
+ timeLine.setEasingCurve(QEasingCurve::CosineCurve);
QCOMPARE(timeLine.valueForTime(0), qreal(0.5));
QCOMPARE(timeLine.valueForTime(250), qreal(1));
QCOMPARE(timeLine.valueForTime(500), qreal(0.5));
@@ -544,7 +751,7 @@ void tst_QTimeLine::outOfRange()
QCOMPARE(timeLine.valueForTime(-100), qreal(0));
QCOMPARE(timeLine.valueForTime(2000), qreal(1));
- timeLine.setCurveShape(QTimeLine::SineCurve);
+ timeLine.setEasingCurve(QEasingCurve::SineCurve);
QCOMPARE(timeLine.valueForTime(2000), qreal(0));
}
@@ -659,6 +866,49 @@ void tst_QTimeLine::setPaused()
}
}
+void tst_QTimeLine::automatedBindableTests()
+{
+ QTimeLine timeLine(200);
+
+ QTestPrivate::testReadWritePropertyBasics(timeLine, 1000, 2000, "duration");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for duration";
+ return;
+ }
+
+ QTestPrivate::testReadWritePropertyBasics(timeLine, 10, 20, "updateInterval");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for updateInterval";
+ return;
+ }
+
+ QTestPrivate::testReadWritePropertyBasics(timeLine, 10, 20, "currentTime");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for currentTime";
+ return;
+ }
+
+ QTestPrivate::testReadWritePropertyBasics(timeLine, QTimeLine::Forward, QTimeLine::Backward,
+ "direction");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for direction";
+ return;
+ }
+
+ QTestPrivate::testReadWritePropertyBasics(timeLine, 4, 5, "loopCount");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for loopCount";
+ return;
+ }
+
+ QTestPrivate::testReadWritePropertyBasics<QTimeLine, QEasingCurve>(
+ timeLine, QEasingCurve::InQuad, QEasingCurve::OutQuad, "easingCurve");
+ if (QTest::currentTestFailed()) {
+ qDebug() << "Failed property test for easingCurve";
+ return;
+ }
+}
+
QTEST_MAIN(tst_QTimeLine)
#include "tst_qtimeline.moc"
diff --git a/tests/auto/corelib/tools/qtyperevision/CMakeLists.txt b/tests/auto/corelib/tools/qtyperevision/CMakeLists.txt
new file mode 100644
index 0000000000..527156e3c2
--- /dev/null
+++ b/tests/auto/corelib/tools/qtyperevision/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtyperevision LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtyperevision
+ SOURCES
+ tst_qtyperevision.cpp
+ LIBRARIES
+ Qt::TestPrivate
+)
diff --git a/tests/auto/corelib/tools/qtyperevision/tst_qtyperevision.cpp b/tests/auto/corelib/tools/qtyperevision/tst_qtyperevision.cpp
new file mode 100644
index 0000000000..66c746382a
--- /dev/null
+++ b/tests/auto/corelib/tools/qtyperevision/tst_qtyperevision.cpp
@@ -0,0 +1,202 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+#include <QtCore/qtyperevision.h>
+#include <QtTest/private/qcomparisontesthelper_p.h>
+
+using namespace Qt::StringLiterals;
+
+class tst_QTypeRevision : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void qTypeRevision_data();
+ void qTypeRevision();
+ void qTypeRevisionTypes();
+ void qTypeRevisionComparisonCompiles();
+ void qTypeRevisionComparison_data();
+ void qTypeRevisionComparison();
+};
+
+template<typename Integer>
+void compileTestRevisionMajorMinor()
+{
+ const Integer major = 8;
+ const Integer minor = 4;
+
+ const QTypeRevision r2 = QTypeRevision::fromVersion(major, minor);
+ QCOMPARE(r2.majorVersion(), 8);
+ QCOMPARE(r2.minorVersion(), 4);
+
+ const QTypeRevision r3 = QTypeRevision::fromMajorVersion(major);
+ QCOMPARE(r3.majorVersion(), 8);
+ QVERIFY(!r3.hasMinorVersion());
+
+ const QTypeRevision r4 = QTypeRevision::fromMinorVersion(minor);
+ QVERIFY(!r4.hasMajorVersion());
+ QCOMPARE(r4.minorVersion(), 4);
+}
+
+
+template<typename Integer>
+void compileTestRevision()
+{
+ if (std::is_signed<Integer>::value)
+ compileTestRevision<typename QIntegerForSize<sizeof(Integer) / 2>::Signed>();
+ else
+ compileTestRevision<typename QIntegerForSize<sizeof(Integer) / 2>::Unsigned>();
+
+ const Integer value = 0x0510;
+ const QTypeRevision r = QTypeRevision::fromEncodedVersion(value);
+
+ QCOMPARE(r.majorVersion(), 5);
+ QCOMPARE(r.minorVersion(), 16);
+ QCOMPARE(r.toEncodedVersion<Integer>(), value);
+
+ compileTestRevisionMajorMinor<Integer>();
+}
+
+template<>
+void compileTestRevision<qint16>()
+{
+ compileTestRevisionMajorMinor<quint8>();
+}
+
+template<>
+void compileTestRevision<quint8>()
+{
+ compileTestRevisionMajorMinor<quint8>();
+}
+
+template<>
+void compileTestRevision<qint8>()
+{
+ compileTestRevisionMajorMinor<qint8>();
+}
+
+void tst_QTypeRevision::qTypeRevision_data()
+{
+ QTest::addColumn<QTypeRevision>("revision");
+ QTest::addColumn<bool>("valid");
+ QTest::addColumn<int>("major");
+ QTest::addColumn<int>("minor");
+
+ QTest::addRow("Qt revision") << QTypeRevision::fromVersion(QT_VERSION_MAJOR, QT_VERSION_MINOR)
+ << true << QT_VERSION_MAJOR << QT_VERSION_MINOR;
+ QTest::addRow("invalid") << QTypeRevision() << false << 0xff << 0xff;
+ QTest::addRow("major") << QTypeRevision::fromMajorVersion(6) << true << 6 << 0xff;
+ QTest::addRow("minor") << QTypeRevision::fromMinorVersion(15) << true << 0xff << 15;
+ QTest::addRow("zero") << QTypeRevision::fromVersion(0, 0) << true << 0 << 0;
+
+ // We're intentionally not testing negative numbers.
+ // There are asserts against negative numbers in QTypeRevision.
+ // You must not pass them as major or minor versions, or values.
+}
+
+void tst_QTypeRevision::qTypeRevision()
+{
+ const QTypeRevision other = QTypeRevision::fromVersion(127, 128);
+
+ QFETCH(QTypeRevision, revision);
+
+ QFETCH(bool, valid);
+ QFETCH(int, major);
+ QFETCH(int, minor);
+
+ QCOMPARE(revision.isValid(), valid);
+ QCOMPARE(revision.majorVersion(), major);
+ QCOMPARE(revision.minorVersion(), minor);
+
+ QCOMPARE(revision.hasMajorVersion(), QTypeRevision::isValidSegment(major));
+ QCOMPARE(revision.hasMinorVersion(), QTypeRevision::isValidSegment(minor));
+
+ const QTypeRevision copy = QTypeRevision::fromEncodedVersion(revision.toEncodedVersion<int>());
+ QCOMPARE(copy, revision);
+
+ QVERIFY(revision != other);
+ QVERIFY(copy != other);
+}
+
+void tst_QTypeRevision::qTypeRevisionTypes()
+{
+ compileTestRevision<quint64>();
+ compileTestRevision<qint64>();
+
+ QVERIFY(!QTypeRevision::isValidSegment(0xff));
+ QVERIFY(!QTypeRevision::isValidSegment(-1));
+
+ const QTypeRevision maxRevision = QTypeRevision::fromVersion(254, 254);
+ QVERIFY(maxRevision.hasMajorVersion());
+ QVERIFY(maxRevision.hasMinorVersion());
+}
+
+void tst_QTypeRevision::qTypeRevisionComparisonCompiles()
+{
+ QTestPrivate::testAllComparisonOperatorsCompile<QTypeRevision>();
+}
+
+void tst_QTypeRevision::qTypeRevisionComparison_data()
+{
+ QTest::addColumn<QTypeRevision>("lhs");
+ QTest::addColumn<QTypeRevision>("rhs");
+ QTest::addColumn<Qt::strong_ordering>("expectedResult");
+
+ static auto versionStr = [](QTypeRevision r) {
+ QByteArray res = r.hasMajorVersion() ? QByteArray::number(r.majorVersion())
+ : "x"_ba;
+ res.append('.');
+ res.append(r.hasMinorVersion() ? QByteArray::number(r.minorVersion())
+ : "x"_ba);
+ return res;
+ };
+
+ const QTypeRevision revisions[] = {
+ QTypeRevision::zero(),
+ QTypeRevision::fromMajorVersion(0),
+ QTypeRevision::fromVersion(0, 1),
+ QTypeRevision::fromVersion(0, 20),
+ QTypeRevision::fromMinorVersion(0),
+ QTypeRevision(),
+ QTypeRevision::fromMinorVersion(1),
+ QTypeRevision::fromMinorVersion(20),
+ QTypeRevision::fromVersion(1, 0),
+ QTypeRevision::fromMajorVersion(1),
+ QTypeRevision::fromVersion(1, 1),
+ QTypeRevision::fromVersion(1, 20),
+ QTypeRevision::fromVersion(20, 0),
+ QTypeRevision::fromMajorVersion(20),
+ QTypeRevision::fromVersion(20, 1),
+ QTypeRevision::fromVersion(20, 20),
+ };
+
+ const int length = sizeof(revisions) / sizeof(QTypeRevision);
+ for (int i = 0; i < length; ++i) {
+ for (int j = i; j < length; ++j) {
+ const Qt::strong_ordering expectedRes = (i == j)
+ ? Qt::strong_ordering::equal
+ : (i < j) ? Qt::strong_ordering::less
+ : Qt::strong_ordering::greater;
+
+ const auto lhs = revisions[i];
+ const auto rhs = revisions[j];
+ QTest::addRow("%s_vs_%s", versionStr(lhs).constData(), versionStr(rhs).constData())
+ << lhs << rhs << expectedRes;
+ }
+ }
+}
+
+void tst_QTypeRevision::qTypeRevisionComparison()
+{
+ QFETCH(const QTypeRevision, lhs);
+ QFETCH(const QTypeRevision, rhs);
+ QFETCH(const Qt::strong_ordering, expectedResult);
+
+ QT_TEST_ALL_COMPARISON_OPS(lhs, rhs, expectedResult);
+}
+
+QTEST_APPLESS_MAIN(tst_QTypeRevision)
+
+#include "tst_qtyperevision.moc"
diff --git a/tests/auto/corelib/tools/quniquehandle/CMakeLists.txt b/tests/auto/corelib/tools/quniquehandle/CMakeLists.txt
new file mode 100644
index 0000000000..fe46826f37
--- /dev/null
+++ b/tests/auto/corelib/tools/quniquehandle/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_quniquehandle LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_quniquehandle
+ SOURCES
+ tst_quniquehandle.cpp
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/tools/quniquehandle/tst_quniquehandle.cpp b/tests/auto/corelib/tools/quniquehandle/tst_quniquehandle.cpp
new file mode 100644
index 0000000000..ed46999e73
--- /dev/null
+++ b/tests/auto/corelib/tools/quniquehandle/tst_quniquehandle.cpp
@@ -0,0 +1,308 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <private/quniquehandle_p.h>
+
+#include <QTest>
+
+QT_USE_NAMESPACE;
+
+// clang-format off
+namespace GlobalResource {
+
+std::array<bool, 3> s_resources = { false, false, false };
+
+using handle = size_t;
+constexpr handle s_invalidHandle = static_cast<handle>(-1);
+
+handle open()
+{
+ const auto it = std::find_if(s_resources.begin(), s_resources.end(),
+ [](bool resource) {
+ return !resource;
+ });
+
+ if (it == s_resources.end())
+ return s_invalidHandle;
+
+ *it = true;
+
+ return std::distance(s_resources.begin(), it);
+}
+
+bool open(handle* dest)
+{
+ const handle resource = open();
+
+ if (resource == s_invalidHandle)
+ return false;
+
+ *dest = resource;
+ return true;
+}
+
+bool close(handle h)
+{
+ if (h >= s_resources.size())
+ return false; // Invalid handle
+
+ if (!s_resources[h])
+ return false; // Un-allocated resource
+
+ s_resources[h] = false;
+ return true;
+}
+
+bool isOpen(handle h)
+{
+ return s_resources[h];
+}
+
+void reset()
+{
+ std::fill(s_resources.begin(), s_resources.end(), false);
+}
+
+bool isReset()
+{
+ return std::all_of(s_resources.begin(), s_resources.end(), [](bool res) {
+ return !res;
+ });
+}
+
+} // namespace GlobalResource
+
+struct TestTraits
+{
+ using Type = GlobalResource::handle;
+
+ static bool close(Type handle)
+ {
+ return GlobalResource::close(handle);
+ }
+
+ static Type invalidValue() noexcept
+ {
+ return GlobalResource::s_invalidHandle;
+ }
+};
+
+using Handle = QUniqueHandle<TestTraits>;
+
+class tst_QUniqueHandle : public QObject
+{
+ Q_OBJECT
+
+private slots:
+
+ void init() const
+ {
+ GlobalResource::reset();
+ }
+
+ void cleanup() const
+ {
+ QVERIFY(GlobalResource::isReset());
+ }
+
+ void defaultConstructor_initializesToInvalidHandle() const
+ {
+ const Handle h;
+ QCOMPARE_EQ(h.get(), TestTraits::invalidValue());
+ }
+
+ void constructor_initializesToValid_whenCalledWithValidHandle() const
+ {
+ const auto res = GlobalResource::open();
+
+ const Handle h{ res };
+
+ QCOMPARE_EQ(h.get(), res);
+ }
+
+ void copyConstructor_and_assignmentOperator_areDeleted() const
+ {
+ static_assert(!std::is_copy_constructible_v<Handle> && !std::is_copy_assignable_v<Handle>);
+ }
+
+ void moveConstructor_movesOwnershipAndResetsSource() const
+ {
+ Handle source{ GlobalResource::open() };
+ const Handle dest{ std::move(source) };
+
+ QVERIFY(!source.isValid());
+ QVERIFY(dest.isValid());
+ QVERIFY(GlobalResource::isOpen(dest.get()));
+ }
+
+ void moveAssignment_movesOwnershipAndResetsSource() const
+ {
+ Handle source{ GlobalResource::open() };
+ Handle dest;
+ dest = { std::move(source) };
+
+ QVERIFY(!source.isValid());
+ QVERIFY(dest.isValid());
+ QVERIFY(GlobalResource::isOpen(dest.get()));
+ }
+
+ void isValid_returnsFalse_onlyWhenHandleIsInvalid() const
+ {
+ const Handle invalid;
+ QVERIFY(!invalid.isValid());
+
+ const Handle valid{ GlobalResource::open() };
+ QVERIFY(valid.isValid());
+ }
+
+ void destructor_callsClose_whenHandleIsValid()
+ {
+ {
+ const Handle h0{ GlobalResource::open() };
+ const Handle h1{ GlobalResource::open() };
+ const Handle h2{ GlobalResource::open() };
+ QVERIFY(!GlobalResource::isReset());
+ }
+
+ QVERIFY(GlobalResource::isReset());
+ }
+
+ void operatorBool_returnsFalse_onlyWhenHandleIsInvalid() const
+ {
+ const Handle invalid;
+ QVERIFY(!invalid);
+
+ const Handle valid{ GlobalResource::open() };
+ QVERIFY(valid);
+ }
+
+ void get_returnsValue() const
+ {
+ const Handle invalid;
+ QCOMPARE_EQ(invalid.get(), GlobalResource::s_invalidHandle);
+
+ const auto resource = GlobalResource::open();
+ const Handle valid{ resource };
+ QCOMPARE_EQ(valid.get(), resource);
+ }
+
+ void reset_resetsPreviousValueAndTakesOwnership() const
+ {
+ const auto resource0 = GlobalResource::open();
+ const auto resource1 = GlobalResource::open();
+
+ Handle h1{ resource0 };
+ h1.reset(resource1);
+
+ QVERIFY(!GlobalResource::isOpen(resource0));
+ QVERIFY(GlobalResource::isOpen(resource1));
+ }
+
+ void release_returnsInvalidResource_whenCalledOnInvalidHandle() const
+ {
+ Handle h;
+ QCOMPARE_EQ(h.release(), GlobalResource::s_invalidHandle);
+ }
+
+ void release_releasesOwnershipAndReturnsResource_whenHandleOwnsObject() const
+ {
+ GlobalResource::handle resource{ GlobalResource::open() };
+ GlobalResource::handle released{};
+ {
+ Handle h{ resource };
+ released = h.release();
+ }
+ QVERIFY(GlobalResource::isOpen(resource));
+ QCOMPARE_EQ(resource, released);
+
+ GlobalResource::close(resource);
+ }
+
+ void swap_swapsOwnership() const
+ {
+ const auto resource0 = GlobalResource::open();
+ const auto resource1 = GlobalResource::open();
+
+ Handle h0{ resource0 };
+ Handle h1{ resource1 };
+
+ std::swap(h0, h1);
+
+ QCOMPARE_EQ(h0.get(), resource1);
+ QCOMPARE_EQ(h1.get(), resource0);
+ }
+
+ void comparison_behavesAsInt_whenHandleTypeIsInt_data() const
+ {
+ QTest::addColumn<int>("lhs");
+ QTest::addColumn<int>("rhs");
+
+ QTest::addRow("lhs == rhs") << 1 << 1;
+ QTest::addRow("lhs < rhs") << 0 << 1;
+ QTest::addRow("lhs > rhs") << 1 << 0;
+ }
+
+ void comparison_behavesAsInt_whenHandleTypeIsInt() const
+ {
+ struct IntTraits
+ {
+ using Type = int;
+
+ static bool close(Type)
+ {
+ return true;
+ }
+
+ static Type invalidValue() noexcept
+ {
+ return INT_MAX;
+ }
+ };
+
+ using Handle = QUniqueHandle<IntTraits>;
+
+ QFETCH(int, lhs);
+ QFETCH(int, rhs);
+
+ QCOMPARE_EQ(Handle{ lhs } == Handle{ rhs }, lhs == rhs);
+ QCOMPARE_EQ(Handle{ lhs } != Handle{ rhs }, lhs != rhs);
+ QCOMPARE_EQ(Handle{ lhs } < Handle{ rhs }, lhs < rhs);
+ QCOMPARE_EQ(Handle{ lhs } <= Handle{ rhs }, lhs <= rhs);
+ QCOMPARE_EQ(Handle{ lhs } > Handle{ rhs }, lhs > rhs);
+ QCOMPARE_EQ(Handle{ lhs } >= Handle{ rhs }, lhs >= rhs);
+
+ QCOMPARE_EQ(Handle{ }, Handle{ });
+ }
+
+ void sort_sortsHandles() const
+ {
+ const auto resource0 = GlobalResource::open();
+ const auto resource1 = GlobalResource::open();
+
+ QVERIFY(resource1 > resource0); // Precondition of underlying allocator
+
+ Handle h0{ resource0 };
+ Handle h1{ resource1 };
+
+ std::vector<Handle> handles;
+ handles.push_back(std::move(h1));
+ handles.push_back(std::move(h0));
+
+ std::sort(handles.begin(), handles.end());
+
+ QCOMPARE_LT(handles.front(), handles.back());
+ QCOMPARE_LT(handles.front().get(), handles.back().get());
+ }
+
+ void addressOf_returnsAddressOfHandle() const
+ {
+ Handle h;
+ QVERIFY(GlobalResource::open(&h));
+ QVERIFY(h.isValid());
+ }
+
+};
+
+// clang-format on
+QTEST_MAIN(tst_QUniqueHandle)
+#include "tst_quniquehandle.moc"
diff --git a/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt b/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt
new file mode 100644
index 0000000000..eccb2634cc
--- /dev/null
+++ b/tests/auto/corelib/tools/qvarlengtharray/CMakeLists.txt
@@ -0,0 +1,20 @@
+# 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
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro b/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro
deleted file mode 100644
index 14b2bc213b..0000000000
--- a/tests/auto/corelib/tools/qvarlengtharray/qvarlengtharray.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qvarlengtharray
-QT = core testlib
-qtConfig(c++14): CONFIG += c++14
-qtConfig(c++1z): CONFIG += c++1z
-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 6220cc766a..6a92663bc4 100644
--- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp
+++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp
@@ -1,47 +1,92 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-#include <qvarlengtharray.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QTest>
+#include <QVarLengthArray>
#include <qvariant.h>
+#include <qscopeguard.h>
+#include <qscopedvaluerollback.h>
+#include <algorithm>
+#include <q20iterator.h>
#include <memory>
+struct Tracker
+{
+ static int count;
+ Tracker() { ++count; }
+ Tracker(const Tracker &) { ++count; }
+ Tracker(Tracker &&) { ++count; }
+
+ Tracker &operator=(const Tracker &) = default;
+ Tracker &operator=(Tracker &&) = default;
+
+ ~Tracker() { --count; }
+
+};
+
+int Tracker::count = 0;
+
+template <typename T>
+class ValueTracker
+{
+ Tracker m_tracker;
+public:
+ ValueTracker() = default;
+ ValueTracker(T value) : value{std::move(value)} {}
+ T value;
+
+ friend bool operator==(const ValueTracker &lhs, const ValueTracker &rhs) noexcept
+ { return lhs.value == rhs.value; }
+ friend bool operator!=(const ValueTracker &lhs, const ValueTracker &rhs) noexcept
+ { 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>(); }
+ void move_int_3() { move_int<3>(); }
+ void move_QString_1() { move_QString<1>(); }
+ void move_QString_2() { move_QString<2>(); }
+ void move_QString_3() { move_QString<3>(); }
+ void move_Tracker_1() { move_Tracker<1>(); }
+ void move_Tracker_2() { move_Tracker<2>(); }
+ void move_Tracker_3() { move_Tracker<3>(); }
void removeLast();
void oldTests();
void appendCausingRealloc();
+ void appendIsStronglyExceptionSafe();
void resize();
void realloc();
+ void iterators();
void reverseIterators();
void count();
void cpp17ctad();
@@ -59,26 +104,74 @@ private slots:
void insertMove();
void nonCopyable();
void implicitDefaultCtor();
-
+ void reserve();
+ void value();
+ void insert();
+ void insert_data();
+ void replace();
+ 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>
+ void move_int() { move<N, int>(42, 24); }
+ template <qsizetype N>
+ void move_QString() { move<N, QString>("Hello", "World"); }
+ template <qsizetype N>
+ void move_Tracker();
template<typename T>
void initializeList();
};
-struct Tracker
+template <typename T>
+void tst_QVarLengthArray::defaultConstructor()
{
- static int count;
- Tracker() { ++count; }
- Tracker(const Tracker &) { ++count; }
- Tracker(Tracker &&) { ++count; }
-
- Tracker &operator=(const Tracker &) = default;
- Tracker &operator=(Tracker &&) = default;
-
- ~Tracker() { --count; }
-};
+ {
+ 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
+ }
+}
-int Tracker::count = 0;
+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()
{
@@ -102,6 +195,112 @@ 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;
+ v.prepend(QString("1"));
+ v.prepend(v.front());
+ QCOMPARE(v.capacity(), 2);
+ // transition from stack to heap
+ v.prepend(v.back());
+ QVERIFY(v.capacity() > 2);
+ QCOMPARE(v.front(), v.back());
+ while (v.size() < v.capacity())
+ v.prepend(v.back());
+ QCOMPARE(v.front(), v.back());
+ QCOMPARE(v.size(), v.capacity());
+ // transition from heap to larger heap:
+ v.prepend(v.back());
+ QCOMPARE(v.front(), v.back());
+}
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 3)
+
+void tst_QVarLengthArray::emplace()
+{
+ {
+ QVarLengthArray<QString, 2> strings;
+ strings.emplace_back();
+ QCOMPARE(strings.size(), 1);
+ QCOMPARE(strings.front().isNull(), true);
+ strings.emplace(strings.begin(), 42, u'x');
+ QCOMPARE(strings.size(), 2);
+ QCOMPARE(strings.back().isNull(), true);
+ QCOMPARE(strings.front(), QString(42, u'x'));
+ auto &r = strings.emplace_back(42, u'y');
+ 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);
+ }
+}
+
+template <qsizetype N>
+void tst_QVarLengthArray::move_Tracker()
+{
+ const auto reset = qScopeGuard([] { Tracker::count = 0; });
+ move<N, ValueTracker<int>>({24}, {24});
+ QCOMPARE(Tracker::count, 0);
+}
+
+template <qsizetype N, typename T>
+void tst_QVarLengthArray::move(T t1, T t2)
+{
+ {
+ QVarLengthArray<T, N> v;
+ v.append(t1);
+ v.append(t2);
+
+ auto moved = std::move(v);
+ QCOMPARE(moved.size(), 2);
+ QCOMPARE(moved[0], t1);
+ QCOMPARE(moved[1], t2);
+
+ v = std::move(moved);
+ QCOMPARE(v.size(), 2);
+ QCOMPARE(v[0], t1);
+ QCOMPARE(v[1], t2);
+ }
+}
+
void tst_QVarLengthArray::removeLast()
{
{
@@ -243,10 +442,109 @@ 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()
{
+ // Empty Movable
+ {
+ QVarLengthArray<QVariant, 1> values;
+ QCOMPARE(values.size(), 0);
+ values.resize(2);
+ QCOMPARE(values.size(), 2);
+ QCOMPARE(values[0], QVariant());
+ QCOMPARE(values[1], QVariant());
+ }
+
+ // Empty POD
+ {
+ QVarLengthArray<int, 1> values;
+ QCOMPARE(values.size(), 0);
+ values.resize(2);
+ QCOMPARE(values.size(), 2);
+ // POD values are uninitialized, but we can check that we can assign
+ // new values
+ values[0] = 0;
+ values[1] = 1;
+
+ QCOMPARE(values[0], 0);
+ QCOMPARE(values[1], 1);
+ }
+
//MOVABLE
{
QVarLengthArray<QVariant,1> values(1);
@@ -346,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) {}
@@ -420,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;
@@ -435,24 +747,33 @@ 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;
};
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(MyPrimitive, Q_PRIMITIVE_TYPE);
-Q_DECLARE_TYPEINFO(MyMovable, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(MyMovable, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(MyComplex, Q_COMPLEX_TYPE);
QT_END_NAMESPACE
bool reallocTestProceed = true;
-template <class T, int PreAlloc>
-int countMoved(QVarLengthArray<T, PreAlloc> const &c)
+template <class T, qsizetype PreAlloc>
+qsizetype countMoved(QVarLengthArray<T, PreAlloc> const &c)
{
- int result = 0;
- for (int i = 0; i < c.size(); ++i)
+ qsizetype result = 0;
+ for (qsizetype i = 0; i < c.size(); ++i)
if (c[i].hasMoved())
++result;
@@ -466,11 +787,11 @@ void reallocTest()
typedef QVarLengthArray<T, 16> Container;
enum {
- isStatic = QTypeInfo<T>::isStatic,
+ isRelocatable = QTypeInfo<T>::isRelocatable,
isComplex = QTypeInfo<T>::isComplex,
- isPrimitive = !isComplex && !isStatic,
- isMovable = !isStatic
+ isPrimitive = !isComplex && isRelocatable,
+ isMovable = isRelocatable
};
// Constructors
@@ -642,8 +963,53 @@ void tst_QVarLengthArray::realloc()
QVERIFY(reallocTestProceed);
}
+void tst_QVarLengthArray::iterators()
+{
+ QVarLengthArray<int> emptyArr;
+ QCOMPARE(emptyArr.constBegin(), emptyArr.constEnd());
+ QCOMPARE(emptyArr.cbegin(), emptyArr.cend());
+ QCOMPARE(emptyArr.begin(), emptyArr.end());
+
+ QVarLengthArray<int> arr { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ auto it = arr.begin();
+ auto constIt = arr.cbegin();
+ qsizetype idx = 0;
+
+ QCOMPARE(*it, arr[idx]);
+ QCOMPARE(*constIt, arr[idx]);
+
+ it++;
+ constIt++;
+ idx++;
+ QCOMPARE(*it, arr[idx]);
+ QCOMPARE(*constIt, arr[idx]);
+
+ it += 5;
+ constIt += 5;
+ idx += 5;
+ QCOMPARE(*it, arr[idx]);
+ QCOMPARE(*constIt, arr[idx]);
+
+ it -= 3;
+ constIt -= 3;
+ idx -= 3;
+ QCOMPARE(*it, arr[idx]);
+ QCOMPARE(*constIt, arr[idx]);
+
+ it--;
+ constIt--;
+ idx--;
+ QCOMPARE(*it, arr[idx]);
+ QCOMPARE(*constIt, arr[idx]);
+}
+
void tst_QVarLengthArray::reverseIterators()
{
+ QVarLengthArray<int> emptyArr;
+ QCOMPARE(emptyArr.crbegin(), emptyArr.crend());
+ QCOMPARE(emptyArr.rbegin(), emptyArr.rend());
+
QVarLengthArray<int> v;
v << 1 << 2 << 3 << 4;
QVarLengthArray<int> vr = v;
@@ -662,26 +1028,29 @@ 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());
}
{
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());
}
{
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());
}
{
@@ -689,9 +1058,10 @@ 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());
}
// test removals too
@@ -700,30 +1070,33 @@ 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());
}
}
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::typeName(qMetaTypeId<decltype(obj)::value_type>()))
+ QMetaType::fromType<decltype(obj)::value_type>().name())
#define CHECK(Type, One, Two, Three) \
do { \
const Type v[] = {One, Two, Three}; \
@@ -740,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()
@@ -756,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()
@@ -778,23 +1147,27 @@ 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()
{
- QVarLengthArray<int> list;
- int sizeOnStack = list.capacity();
- int sizeOnHeap = sizeOnStack * 2;
+ QVarLengthArray<int, 100> list;
+ qsizetype sizeOnStack = list.capacity();
+ QCOMPARE(sizeOnStack, 100);
+ list.squeeze();
+ QCOMPARE(list.capacity(), sizeOnStack);
+
+ qsizetype sizeOnHeap = sizeOnStack * 2;
list.resize(0);
QCOMPARE(list.capacity(), sizeOnStack);
list.resize(sizeOnHeap);
@@ -815,11 +1188,11 @@ void tst_QVarLengthArray::squeeze()
void tst_QVarLengthArray::operators()
{
- QVarLengthArray<QString> myvla;
+ QVarLengthArray<QString, 6> myvla;
myvla << "A" << "B" << "C";
- QVarLengthArray<QString> myvlatwo;
+ QVarLengthArray<QString, 3> myvlatwo;
myvlatwo << "D" << "E" << "F";
- QVarLengthArray<QString> combined;
+ QVarLengthArray<QString, 7> combined;
combined << "A" << "B" << "C" << "D" << "E" << "F";
// !=
@@ -827,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);
@@ -859,6 +1232,10 @@ void tst_QVarLengthArray::operators()
void tst_QVarLengthArray::indexOf()
{
QVarLengthArray<QString> myvec;
+
+ QCOMPARE(myvec.indexOf("A"), -1);
+ QCOMPARE(myvec.indexOf("A", 5), -1);
+
myvec << "A" << "B" << "C" << "B" << "A";
QVERIFY(myvec.indexOf("B") == 1);
@@ -883,6 +1260,10 @@ void tst_QVarLengthArray::indexOf()
void tst_QVarLengthArray::lastIndexOf()
{
QVarLengthArray<QString> myvec;
+
+ QCOMPARE(myvec.lastIndexOf("A"), -1);
+ QCOMPARE(myvec.lastIndexOf("A", 5), -1);
+
myvec << "A" << "B" << "C" << "B" << "A";
QVERIFY(myvec.lastIndexOf("B") == 3);
@@ -906,6 +1287,10 @@ void tst_QVarLengthArray::lastIndexOf()
void tst_QVarLengthArray::contains()
{
QVarLengthArray<QString> myvec;
+
+ QVERIFY(!myvec.contains(QLatin1String("aaa")));
+ QVERIFY(!myvec.contains(QString()));
+
myvec << "aaa" << "bbb" << "ccc";
QVERIFY(myvec.contains(QLatin1String("aaa")));
@@ -921,6 +1306,9 @@ void tst_QVarLengthArray::contains()
void tst_QVarLengthArray::clear()
{
QVarLengthArray<QString, 5> myvec;
+ QCOMPARE(myvec.size(), 0);
+ myvec.clear();
+ QCOMPARE(myvec.size(), 0);
for (int i = 0; i < 10; ++i)
myvec << "aaa";
@@ -1000,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;
@@ -1025,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));
@@ -1097,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());
@@ -1131,5 +1530,239 @@ void tst_QVarLengthArray::implicitDefaultCtor()
QCOMPARE(def.size(), 0);
}
+void tst_QVarLengthArray::reserve()
+{
+ QVarLengthArray<int, 100> arr;
+ QCOMPARE(arr.capacity(), 100);
+ QCOMPARE(arr.size(), 0);
+
+ const auto *stackPtr = arr.constData();
+ arr.reserve(50);
+ // Nothing changed, as we reserve less than pre-allocated
+ QCOMPARE(arr.capacity(), 100);
+ QCOMPARE(arr.size(), 0);
+ QCOMPARE(arr.constData(), stackPtr);
+
+ arr.reserve(150);
+ // Allocate memory on heap, as we reserve more than pre-allocated
+ QCOMPARE(arr.capacity(), 150);
+ QCOMPARE(arr.size(), 0);
+ const auto *heapPtr = arr.constData();
+ QVERIFY(heapPtr != stackPtr);
+
+ arr.reserve(50);
+ // Nothing changed
+ QCOMPARE(arr.capacity(), 150);
+ QCOMPARE(arr.constData(), heapPtr);
+
+ arr.squeeze();
+ // After squeeze() we go back to using stack
+ QCOMPARE(arr.capacity(), 100);
+ QCOMPARE(arr.constData(), stackPtr);
+}
+
+void tst_QVarLengthArray::value()
+{
+ const QString def("default value");
+
+ QVarLengthArray<QString> arr;
+ QCOMPARE(arr.value(0), QString());
+ QCOMPARE(arr.value(1, def), def);
+ QCOMPARE(arr.value(-1, def), def);
+
+ const qsizetype size = 5;
+ const QString dataStr("data%1");
+ arr.resize(size);
+ for (qsizetype i = 0; i < size; ++i)
+ arr[i] = dataStr.arg(i);
+
+ for (qsizetype i = 0; i < size; ++i)
+ QCOMPARE(arr.value(i, def), dataStr.arg(i));
+
+ QCOMPARE(arr.value(size + 1), QString());
+ QCOMPARE(arr.value(-1, def), def);
+}
+
+void tst_QVarLengthArray::insert()
+{
+ QFETCH(QVarLengthArray<QString>, arr);
+ QFETCH(int, pos);
+ QFETCH(int, count);
+ QFETCH(QString, data);
+ QFETCH(QVarLengthArray<QString>, expected);
+
+ // Insert using index
+ {
+ QVarLengthArray<QString> copy = arr;
+ if (count == 1) {
+ copy.insert(pos, data);
+ QCOMPARE(copy, expected);
+
+ copy = arr;
+ QString d = data;
+ copy.insert(pos, std::move(d));
+ QCOMPARE(copy, expected);
+ } else {
+ copy.insert(pos, count, data);
+ QCOMPARE(copy, expected);
+ }
+ }
+
+ // Insert using iterator
+ {
+ QVarLengthArray<QString> copy = arr;
+ if (count == 1) {
+ copy.insert(copy.cbegin() + pos, data);
+ QCOMPARE(copy, expected);
+
+ copy = arr;
+ QString d = data;
+ copy.insert(copy.cbegin() + pos, std::move(d));
+ QCOMPARE(copy, expected);
+ } else {
+ copy.insert(copy.cbegin() + pos, count, data);
+ QCOMPARE(copy, expected);
+ }
+ }
+}
+
+void tst_QVarLengthArray::insert_data()
+{
+ QTest::addColumn<QVarLengthArray<QString>>("arr");
+ QTest::addColumn<int>("pos");
+ QTest::addColumn<int>("count");
+ QTest::addColumn<QString>("data");
+ QTest::addColumn<QVarLengthArray<QString>>("expected");
+
+ const QString data("Test");
+
+ QTest::newRow("empty")
+ << QVarLengthArray<QString>() << 0 << 1 << data << QVarLengthArray<QString>({ data });
+ QTest::newRow("empty-none")
+ << QVarLengthArray<QString>() << 0 << 0 << data << QVarLengthArray<QString>();
+ QTest::newRow("begin")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 0 << 1 << data
+ << QVarLengthArray<QString>({ data, "value1", "value2" });
+ QTest::newRow("end")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 2 << 1 << data
+ << QVarLengthArray<QString>({ "value1", "value2", data });
+ QTest::newRow("middle")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 1 << 1 << data
+ << QVarLengthArray<QString>({ "value1", data, "value2" });
+ QTest::newRow("begin-none")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 0 << 0 << data
+ << QVarLengthArray<QString>({ "value1", "value2" });
+ QTest::newRow("end-none")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 2 << 0 << data
+ << QVarLengthArray<QString>({ "value1", "value2" });
+ QTest::newRow("middle-none")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 1 << 0 << data
+ << QVarLengthArray<QString>({ "value1", "value2" });
+ QTest::newRow("multi begin")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 0 << 2 << data
+ << QVarLengthArray<QString>({ data, data, "value1", "value2" });
+ QTest::newRow("multi end")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 2 << 2 << data
+ << QVarLengthArray<QString>({ "value1", "value2", data, data });
+ QTest::newRow("multi middle")
+ << QVarLengthArray<QString>({ "value1", "value2" }) << 1 << 2 << data
+ << QVarLengthArray<QString>({ "value1", data, data, "value2" });
+}
+
+void tst_QVarLengthArray::replace()
+{
+ QVarLengthArray<QString> arr({ "val0", "val1", "val2" });
+
+ arr.replace(0, "data0");
+ QCOMPARE(arr, QVarLengthArray<QString>({ "data0", "val1", "val2" }));
+
+ arr.replace(2, "data2");
+ QCOMPARE(arr, QVarLengthArray<QString>({ "data0", "val1", "data2" }));
+
+ arr.replace(1, "data1");
+ QCOMPARE(arr, QVarLengthArray<QString>({ "data0", "data1", "data2" }));
+}
+
+void tst_QVarLengthArray::remove()
+{
+ auto isVal2 = [](const QString &str) { return str == "val2"; };
+
+ QVarLengthArray<QString> arr;
+ QCOMPARE(arr.removeAll("val0"), 0);
+ QVERIFY(!arr.removeOne("val1"));
+ QCOMPARE(arr.removeIf(isVal2), 0);
+
+ arr << "val0" << "val1" << "val2";
+ arr << "val0" << "val1" << "val2";
+ arr << "val0" << "val1" << "val2";
+
+ QCOMPARE(arr.size(), 9);
+
+ arr.remove(1, 3);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val1", "val2", "val0", "val1", "val2" }));
+
+ arr.remove(2);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val1", "val0", "val1", "val2" }));
+
+ QVERIFY(arr.removeOne("val1"));
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val0", "val1", "val2" }));
+
+ QCOMPARE(arr.removeAll("val0"), 2);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val1", "val2" }));
+
+ QCOMPARE(arr.removeIf(isVal2), 1);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val1" }));
+
+ arr.removeLast();
+ QVERIFY(arr.isEmpty());
+}
+
+void tst_QVarLengthArray::erase()
+{
+ QVarLengthArray<QString> arr;
+ QCOMPARE(arr.erase(arr.cbegin(), arr.cend()), arr.cend());
+
+ arr << "val0" << "val1" << "val2";
+ arr << "val0" << "val1" << "val2";
+ arr << "val0" << "val1" << "val2";
+
+ auto it = arr.erase(arr.cbegin() + 1, arr.cend() - 3);
+ QCOMPARE(it, arr.cend() - 3);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val0", "val1", "val2" }));
+
+ it = arr.erase(arr.cbegin());
+ QCOMPARE(it, arr.cbegin());
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val1", "val2" }));
+
+ it = arr.erase(arr.cbegin() + 1);
+ QCOMPARE(it, arr.cend() - 1);
+ QCOMPARE(arr, QVarLengthArray<QString>({ "val0", "val2" }));
+
+ it = arr.erase(arr.cend() - 1);
+ QCOMPARE(it, arr.cend());
+ 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"
diff --git a/tests/auto/corelib/tools/qvector/qvector.pro b/tests/auto/corelib/tools/qvector/qvector.pro
deleted file mode 100644
index 689d9b87a2..0000000000
--- a/tests/auto/corelib/tools/qvector/qvector.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-CONFIG += testcase
-qtConfig(c++11): CONFIG += c++11
-qtConfig(c++14): CONFIG += c++14
-qtConfig(c++1z): CONFIG += c++1z
-TARGET = tst_qvector
-QT = core testlib
-SOURCES = $$PWD/tst_qvector.cpp
diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp
deleted file mode 100644
index 7a69e844d4..0000000000
--- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp
+++ /dev/null
@@ -1,2649 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-#include <QAtomicInt>
-#include <QThread>
-#include <QSemaphore>
-#include <qvector.h>
-
-struct Movable {
- Movable(char input = 'j')
- : i(input)
- , that(this)
- , state(Constructed)
- {
- counter.fetchAndAddRelaxed(1);
- }
- Movable(const Movable &other)
- : i(other.i)
- , that(this)
- , state(Constructed)
- {
- check(other.state, Constructed);
- counter.fetchAndAddRelaxed(1);
- }
- Movable(Movable &&other)
- : i(other.i)
- , that(other.that)
- , state(Constructed)
- {
- check(other.state, Constructed);
- counter.fetchAndAddRelaxed(1);
- other.that = nullptr;
- }
-
- ~Movable()
- {
- check(state, Constructed);
- i = 0;
- counter.fetchAndAddRelaxed(-1);
- state = Destructed;
- }
-
- bool operator ==(const Movable &other) const
- {
- check(state, Constructed);
- check(other.state, Constructed);
- return i == other.i;
- }
-
- Movable &operator=(const Movable &other)
- {
- check(state, Constructed);
- check(other.state, Constructed);
- i = other.i;
- that = this;
- return *this;
- }
- Movable &operator=(Movable &&other)
- {
- check(state, Constructed);
- check(other.state, Constructed);
- i = other.i;
- that = other.that;
- other.that = nullptr;
- return *this;
- }
- bool wasConstructedAt(const Movable *other) const
- {
- return that == other;
- }
- char i;
- static QAtomicInt counter;
-private:
- Movable *that; // used to check if an instance was moved
-
- enum State { Constructed = 106, Destructed = 110 };
- State state;
-
- static void check(const State state1, const State state2)
- {
- QCOMPARE(int(state1), int(state2));
- }
-};
-
-inline uint qHash(const Movable &key, uint seed = 0) { return qHash(key.i, seed); }
-
-QAtomicInt Movable::counter = 0;
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Movable);
-
-struct Custom {
- Custom(char input = 'j')
- : i(input)
- , that(this)
- , state(Constructed)
- {
- counter.fetchAndAddRelaxed(1);
- }
- Custom(const Custom &other)
- : that(this)
- , state(Constructed)
- {
- check(&other);
- counter.fetchAndAddRelaxed(1);
- this->i = other.i;
- }
- ~Custom()
- {
- check(this);
- i = 0;
- counter.fetchAndAddRelaxed(-1);
- state = Destructed;
- }
-
- bool operator ==(const Custom &other) const
- {
- check(&other);
- check(this);
- return i == other.i;
- }
-
- bool operator<(const Custom &other) const
- {
- check(&other);
- check(this);
- return i < other.i;
- }
-
- Custom &operator=(const Custom &other)
- {
- check(&other);
- check(this);
- i = other.i;
- return *this;
- }
- static QAtomicInt counter;
-
- char i; // used to identify orgin of an instance
-private:
- Custom *that; // used to check if an instance was moved
-
- enum State { Constructed = 106, Destructed = 110 };
- State state;
-
- static void check(const Custom *c)
- {
- // check if c object has been moved
- QCOMPARE(c, c->that);
- QCOMPARE(int(c->state), int(Constructed));
- }
-};
-QAtomicInt Custom::counter = 0;
-
-inline uint qHash(const Custom &key, uint seed = 0) { return qHash(key.i, seed); }
-
-Q_DECLARE_METATYPE(Custom);
-
-// tests depends on the fact that:
-Q_STATIC_ASSERT(!QTypeInfo<int>::isStatic);
-Q_STATIC_ASSERT(!QTypeInfo<int>::isComplex);
-Q_STATIC_ASSERT(!QTypeInfo<Movable>::isStatic);
-Q_STATIC_ASSERT(QTypeInfo<Movable>::isComplex);
-Q_STATIC_ASSERT(QTypeInfo<Custom>::isStatic);
-Q_STATIC_ASSERT(QTypeInfo<Custom>::isComplex);
-
-
-class tst_QVector : public QObject
-{
- Q_OBJECT
-private slots:
- void constructors_empty() const;
- void constructors_emptyReserveZero() const;
- void constructors_emptyReserve() const;
- void constructors_reserveAndInitialize() const;
- void copyConstructorInt() const;
- void copyConstructorMovable() const;
- void copyConstructorCustom() const;
- void assignmentInt() const;
- void assignmentMovable() const;
- void assignmentCustom() const;
- void assignFromInitializerListInt() const;
- void assignFromInitializerListMovable() const;
- void assignFromInitializerListCustom() const;
- void addInt() const;
- void addMovable() const;
- void addCustom() const;
- void appendInt() const;
- void appendMovable() const;
- void appendCustom() const;
- void appendRvalue() const;
- void at() const;
- void capacityInt() const;
- void capacityMovable() const;
- void capacityCustom() const;
- void clearInt() const;
- void clearMovable() const;
- void clearCustom() const;
- void constData() const;
- void constFirst() const;
- void constLast() const;
- void contains() const;
- void countInt() const;
- void countMovable() const;
- void countCustom() const;
- void cpp17ctad() const;
- void data() const;
- void emptyInt() const;
- void emptyMovable() const;
- void emptyCustom() const;
- void endsWith() const;
- void eraseEmptyInt() const;
- void eraseEmptyMovable() const;
- void eraseEmptyCustom() const;
- void eraseEmptyReservedInt() const;
- void eraseEmptyReservedMovable() const;
- void eraseEmptyReservedCustom() const;
- void eraseInt() const;
- void eraseIntShared() const;
- void eraseMovable() const;
- void eraseMovableShared() const;
- void eraseCustom() const;
- void eraseCustomShared() const;
- void eraseReservedInt() const;
- void eraseReservedMovable() const;
- void eraseReservedCustom() const;
- void fillInt() const;
- void fillMovable() const;
- void fillCustom() const;
- void fillDetaches() const;
- void first() const;
- void fromListInt() const;
- void fromListMovable() const;
- void fromListCustom() const;
- void indexOf() const;
- void insertInt() const;
- void insertMovable() const;
- void insertCustom() const;
- void isEmpty() const;
- void last() const;
- void lastIndexOf() const;
- void mid() const;
- void moveInt() const;
- void moveMovable() const;
- void moveCustom() const;
- void prependInt() const;
- void prependMovable() const;
- void prependCustom() const;
- void qhashInt() const { qhash<int>(); }
- void qhashMovable() const { qhash<Movable>(); }
- void qhashCustom() const { qhash<Custom>(); }
- void removeAllWithAlias() const;
- void removeInt() const;
- void removeMovable() const;
- void removeCustom() const;
- void removeFirstLast() const;
- void resizePOD_data() const;
- void resizePOD() const;
- void resizeComplexMovable_data() const;
- void resizeComplexMovable() const;
- void resizeComplex_data() const;
- void resizeComplex() const;
- void resizeCtorAndDtor() const;
- void reverseIterators() const;
- void sizeInt() const;
- void sizeMovable() const;
- void sizeCustom() const;
- void startsWith() const;
- void swapInt() const;
- void swapMovable() const;
- void swapCustom() const;
- void toList() const;
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- void fromStdVector() const;
- void toStdVector() const;
-#endif
- void value() const;
-
- void testOperators() const;
-
- void reserve();
- void reserveZero();
- void initializeListInt();
- void initializeListMovable();
- void initializeListCustom();
-
- void const_shared_null();
-
- void detachInt() const;
- void detachMovable() const;
- void detachCustom() const;
- void detachThreadSafetyInt() const;
- void detachThreadSafetyMovable() const;
- void detachThreadSafetyCustom() const;
-
- void insertMove() const;
-
- void swapItemsAt() const;
-
-private:
- template<typename T> void copyConstructor() const;
- template<typename T> void add() const;
- template<typename T> void append() const;
- template<typename T> void assignFromInitializerList() const;
- template<typename T> void capacity() const;
- template<typename T> void clear() const;
- template<typename T> void count() const;
- template<typename T> void empty() const;
- template<typename T> void eraseEmpty() const;
- template<typename T> void eraseEmptyReserved() const;
- template<typename T> void erase(bool shared) const;
- template<typename T> void eraseReserved() const;
- template<typename T> void fill() const;
- template<typename T> void fromList() const;
- template<typename T> void insert() const;
- template<typename T> void qhash() const;
- template<typename T> void move() const;
- template<typename T> void prepend() const;
- template<typename T> void remove() const;
- template<typename T> void size() const;
- template<typename T> void swap() const;
- template<typename T> void initializeList();
- template<typename T> void detach() const;
- template<typename T> void detachThreadSafety() const;
-};
-
-
-template<typename T> struct SimpleValue
-{
- static T at(int index)
- {
- return Values[index % MaxIndex];
- }
-
- static QVector<T> vector(int size)
- {
- QVector<T> ret;
- for (int i = 0; i < size; i++)
- ret.append(at(i));
- return ret;
- }
-
- static const uint MaxIndex = 6;
- static const T Values[MaxIndex];
-};
-
-template<>
-const int SimpleValue<int>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Movable SimpleValue<Movable>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Custom SimpleValue<Custom>::Values[] = { 110, 105, 101, 114, 111, 98 };
-
-// Make some macros for the tests to use in order to be slightly more readable...
-#define T_FOO SimpleValue<T>::at(0)
-#define T_BAR SimpleValue<T>::at(1)
-#define T_BAZ SimpleValue<T>::at(2)
-#define T_CAT SimpleValue<T>::at(3)
-#define T_DOG SimpleValue<T>::at(4)
-#define T_BLAH SimpleValue<T>::at(5)
-
-void tst_QVector::constructors_empty() const
-{
- QVector<int> emptyInt;
- QVector<Movable> emptyMovable;
- QVector<Custom> emptyCustom;
-}
-
-void tst_QVector::constructors_emptyReserveZero() const
-{
- QVector<int> emptyInt(0);
- QVector<Movable> emptyMovable(0);
- QVector<Custom> emptyCustom(0);
-}
-
-void tst_QVector::constructors_emptyReserve() const
-{
- // pre-reserve capacity
- QVector<int> myInt(5);
- QVERIFY(myInt.capacity() == 5);
- QVector<Movable> myMovable(5);
- QVERIFY(myMovable.capacity() == 5);
- QVector<Custom> myCustom(4);
- QVERIFY(myCustom.capacity() == 4);
-}
-
-void tst_QVector::constructors_reserveAndInitialize() const
-{
- // default-initialise items
-
- QVector<int> myInt(5, 42);
- QVERIFY(myInt.capacity() == 5);
- foreach (int meaningoflife, myInt) {
- QCOMPARE(meaningoflife, 42);
- }
-
- QVector<QString> myString(5, QString::fromLatin1("c++"));
- QVERIFY(myString.capacity() == 5);
- // make sure all items are initialised ok
- foreach (QString meaningoflife, myString) {
- QCOMPARE(meaningoflife, QString::fromLatin1("c++"));
- }
-
- QVector<Custom> myCustom(5, Custom('n'));
- QVERIFY(myCustom.capacity() == 5);
- // make sure all items are initialised ok
- foreach (Custom meaningoflife, myCustom) {
- QCOMPARE(meaningoflife.i, 'n');
- }
-}
-
-template<typename T>
-void tst_QVector::copyConstructor() const
-{
- T value1(SimpleValue<T>::at(0));
- T value2(SimpleValue<T>::at(1));
- T value3(SimpleValue<T>::at(2));
- T value4(SimpleValue<T>::at(3));
- {
- QVector<T> v1;
- QVector<T> v2(v1);
- QCOMPARE(v1, v2);
- }
- {
- QVector<T> v1;
- v1 << value1 << value2 << value3 << value4;
- QVector<T> v2(v1);
- QCOMPARE(v1, v2);
- }
-}
-
-void tst_QVector::copyConstructorInt() const
-{
- copyConstructor<int>();
-}
-
-void tst_QVector::copyConstructorMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- copyConstructor<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::copyConstructorCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- copyConstructor<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template <class T>
-static inline void testAssignment()
-{
- QVector<T> v1(5);
- QCOMPARE(v1.size(), 5);
- QVERIFY(v1.isDetached());
-
- QVector<T> v2(7);
- QCOMPARE(v2.size(), 7);
- QVERIFY(v2.isDetached());
-
- QVERIFY(!v1.isSharedWith(v2));
-
- v1 = v2;
-
- QVERIFY(!v1.isDetached());
- QVERIFY(!v2.isDetached());
- QVERIFY(v1.isSharedWith(v2));
-
- const void *const data1 = v1.constData();
- const void *const data2 = v2.constData();
-
- QCOMPARE(data1, data2);
-
- v1.clear();
-
- QVERIFY(v2.isDetached());
- QVERIFY(!v1.isSharedWith(v2));
- QCOMPARE((void *)v2.constData(), data2);
-}
-
-void tst_QVector::assignmentInt() const
-{
- testAssignment<int>();
-}
-
-void tst_QVector::assignmentMovable() const
-{
- testAssignment<Movable>();
-}
-
-void tst_QVector::assignmentCustom() const
-{
- testAssignment<Custom>();
-}
-
-template<typename T>
-void tst_QVector::assignFromInitializerList() const
-{
- T val1(SimpleValue<T>::at(1));
- T val2(SimpleValue<T>::at(2));
- T val3(SimpleValue<T>::at(3));
-
- QVector<T> v1 = {val1, val2, val3};
- QCOMPARE(v1, QVector<T>() << val1 << val2 << val3);
- QCOMPARE(v1, (QVector<T> {val1, val2, val3}));
-
- v1 = {};
- QCOMPARE(v1.size(), 0);
-}
-
-void tst_QVector::assignFromInitializerListInt() const
-{
- assignFromInitializerList<int>();
-}
-
-void tst_QVector::assignFromInitializerListMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- assignFromInitializerList<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::assignFromInitializerListCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- assignFromInitializerList<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::add() const
-{
- {
- QVector<T> empty1;
- QVector<T> empty2;
- QVERIFY((empty1 + empty2).isEmpty());
- empty1 += empty2;
- QVERIFY(empty1.isEmpty());
- QVERIFY(empty2.isEmpty());
- }
- {
- QVector<T> v(12);
- QVector<T> empty;
- QCOMPARE((v + empty), v);
- v += empty;
- QVERIFY(!v.isEmpty());
- QCOMPARE(v.size(), 12);
- QVERIFY(empty.isEmpty());
- }
- {
- QVector<T> v1(12);
- QVector<T> v2;
- v2 += v1;
- QVERIFY(!v1.isEmpty());
- QCOMPARE(v1.size(), 12);
- QVERIFY(!v2.isEmpty());
- QCOMPARE(v2.size(), 12);
- }
-}
-
-void tst_QVector::addInt() const
-{
- add<int>();
-}
-
-void tst_QVector::addMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- add<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::addCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- add<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::append() const
-{
- {
- QVector<T> myvec;
- myvec.append(SimpleValue<T>::at(0));
- QVERIFY(myvec.size() == 1);
- myvec.append(SimpleValue<T>::at(1));
- QVERIFY(myvec.size() == 2);
- myvec.append(SimpleValue<T>::at(2));
- QVERIFY(myvec.size() == 3);
-
- QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(0)
- << SimpleValue<T>::at(1)
- << SimpleValue<T>::at(2));
- }
- {
- QVector<T> v(2);
- v.append(SimpleValue<T>::at(0));
- QVERIFY(v.size() == 3);
- QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
- }
- {
- QVector<T> v(2);
- v.reserve(12);
- v.append(SimpleValue<T>::at(0));
- QVERIFY(v.size() == 3);
- QCOMPARE(v.at(v.size() - 1), SimpleValue<T>::at(0));
- }
- {
- QVector<int> v;
- v << 1 << 2 << 3;
- QVector<int> x;
- x << 4 << 5 << 6;
- v.append(x);
-
- QVector<int> combined;
- combined << 1 << 2 << 3 << 4 << 5 << 6;
-
- QCOMPARE(v, combined);
- }
-}
-
-void tst_QVector::appendInt() const
-{
- append<int>();
-}
-
-void tst_QVector::appendMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- append<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::appendCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- append<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::appendRvalue() const
-{
- QVector<QString> v;
- v.append("hello");
- QString world = "world";
- v.append(std::move(world));
- QVERIFY(world.isEmpty());
- QCOMPARE(v.front(), QString("hello"));
- QCOMPARE(v.back(), QString("world"));
-}
-
-void tst_QVector::at() const
-{
- QVector<QString> myvec;
- myvec << "foo" << "bar" << "baz";
-
- QVERIFY(myvec.size() == 3);
- QCOMPARE(myvec.at(0), QLatin1String("foo"));
- QCOMPARE(myvec.at(1), QLatin1String("bar"));
- QCOMPARE(myvec.at(2), QLatin1String("baz"));
-
- // append an item
- myvec << "hello";
- QVERIFY(myvec.size() == 4);
- QCOMPARE(myvec.at(0), QLatin1String("foo"));
- QCOMPARE(myvec.at(1), QLatin1String("bar"));
- QCOMPARE(myvec.at(2), QLatin1String("baz"));
- QCOMPARE(myvec.at(3), QLatin1String("hello"));
-
- // remove an item
- myvec.remove(1);
- QVERIFY(myvec.size() == 3);
- QCOMPARE(myvec.at(0), QLatin1String("foo"));
- QCOMPARE(myvec.at(1), QLatin1String("baz"));
- QCOMPARE(myvec.at(2), QLatin1String("hello"));
-}
-
-template<typename T>
-void tst_QVector::capacity() const
-{
- QVector<T> myvec;
-
- // TODO: is this guaranteed? seems a safe assumption, but I suppose preallocation of a
- // few items isn't an entirely unforseeable possibility.
- QVERIFY(myvec.capacity() == 0);
-
- // test it gets a size
- myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
- QVERIFY(myvec.capacity() >= 3);
-
- // make sure it grows ok
- myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
- QVERIFY(myvec.capacity() >= 6);
- // let's try squeeze a bit
- myvec.remove(3);
- myvec.remove(3);
- myvec.remove(3);
- myvec.squeeze();
- QVERIFY(myvec.capacity() >= 3);
-
- myvec.remove(0);
- myvec.remove(0);
- myvec.remove(0);
- myvec.squeeze();
- QVERIFY(myvec.capacity() == 0);
-}
-
-void tst_QVector::capacityInt() const
-{
- capacity<int>();
-}
-
-void tst_QVector::capacityMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- capacity<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::capacityCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- capacity<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::clear() const
-{
- QVector<T> myvec;
- myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
-
- const auto oldCapacity = myvec.capacity();
- QCOMPARE(myvec.size(), 3);
- myvec.clear();
- QCOMPARE(myvec.size(), 0);
- QCOMPARE(myvec.capacity(), oldCapacity);
-}
-
-void tst_QVector::clearInt() const
-{
- clear<int>();
-}
-
-void tst_QVector::clearMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- clear<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::clearCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- clear<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::constData() const
-{
- int arr[] = { 42, 43, 44 };
- QVector<int> myvec;
- myvec << 42 << 43 << 44;
-
- QVERIFY(memcmp(myvec.constData(), reinterpret_cast<const int *>(&arr), sizeof(int) * 3) == 0);
-}
-
-void tst_QVector::contains() const
-{
- QVector<QString> myvec;
- myvec << "aaa" << "bbb" << "ccc";
-
- QVERIFY(myvec.contains(QLatin1String("aaa")));
- QVERIFY(myvec.contains(QLatin1String("bbb")));
- QVERIFY(myvec.contains(QLatin1String("ccc")));
- QVERIFY(!myvec.contains(QLatin1String("I don't exist")));
-
- // add it and make sure it does :)
- myvec.append(QLatin1String("I don't exist"));
- QVERIFY(myvec.contains(QLatin1String("I don't exist")));
-}
-
-template<typename T>
-void tst_QVector::count() const
-{
- // total size
- {
- // zero size
- QVector<T> myvec;
- QVERIFY(myvec.count() == 0);
-
- // grow
- myvec.append(SimpleValue<T>::at(0));
- QVERIFY(myvec.count() == 1);
- myvec.append(SimpleValue<T>::at(1));
- QVERIFY(myvec.count() == 2);
-
- // shrink
- myvec.remove(0);
- QVERIFY(myvec.count() == 1);
- myvec.remove(0);
- QVERIFY(myvec.count() == 0);
- }
-
- // count of items
- {
- QVector<T> myvec;
- myvec << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2);
-
- // initial tests
- QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
- QVERIFY(myvec.count(SimpleValue<T>::at(3)) == 0);
-
- // grow
- myvec.append(SimpleValue<T>::at(0));
- QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 2);
-
- // shrink
- myvec.remove(0);
- QVERIFY(myvec.count(SimpleValue<T>::at(0)) == 1);
- }
-}
-
-void tst_QVector::countInt() const
-{
- count<int>();
-}
-
-void tst_QVector::countMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- count<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::countCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- count<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::cpp17ctad() const
-{
-#ifdef __cpp_deduction_guides
-#define QVERIFY_IS_VECTOR_OF(obj, Type) \
- QVERIFY2((std::is_same<decltype(obj), QVector<Type>>::value), \
- QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>()))
-#define CHECK(Type, One, Two, Three) \
- do { \
- const Type v[] = {One, Two, Three}; \
- QVector v1 = {One, Two, Three}; \
- QVERIFY_IS_VECTOR_OF(v1, Type); \
- QVector v2(v1.begin(), v1.end()); \
- QVERIFY_IS_VECTOR_OF(v2, Type); \
- QVector v3(std::begin(v), std::end(v)); \
- QVERIFY_IS_VECTOR_OF(v3, Type); \
- } while (false) \
- /*end*/
- CHECK(int, 1, 2, 3);
- CHECK(double, 1.0, 2.0, 3.0);
- CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
-#undef QVERIFY_IS_VECTOR_OF
-#undef CHECK
-#else
- QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler.");
-#endif
-}
-
-void tst_QVector::data() const
-{
- QVector<int> myvec;
- myvec << 42 << 43 << 44;
-
- // make sure it starts off ok
- QCOMPARE(*(myvec.data() + 1), 43);
-
- // alter it
- *(myvec.data() + 1) = 69;
-
- // check it altered
- QCOMPARE(*(myvec.data() + 1), 69);
-
- int arr[] = { 42, 69, 44 };
- QVERIFY(memcmp(myvec.data(), reinterpret_cast<int *>(&arr), sizeof(int) * 3) == 0);
-}
-
-template<typename T>
-void tst_QVector::empty() const
-{
- QVector<T> myvec;
-
- // starts empty
- QVERIFY(myvec.empty());
-
- // not empty
- myvec.append(SimpleValue<T>::at(2));
- QVERIFY(!myvec.empty());
-
- // empty again
- myvec.remove(0);
- QVERIFY(myvec.empty());
-}
-
-void tst_QVector::emptyInt() const
-{
- empty<int>();
-}
-
-void tst_QVector::emptyMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- empty<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::emptyCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- empty<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::endsWith() const
-{
- QVector<int> myvec;
-
- // empty vector
- QVERIFY(!myvec.endsWith(1));
-
- // add the one, should work
- myvec.append(1);
- QVERIFY(myvec.endsWith(1));
-
- // add something else, fails now
- myvec.append(3);
- QVERIFY(!myvec.endsWith(1));
-
- // remove it again :)
- myvec.remove(1);
- QVERIFY(myvec.endsWith(1));
-}
-
-template<typename T>
-void tst_QVector::eraseEmpty() const
-{
- QVector<T> v;
- v.erase(v.begin(), v.end());
- QCOMPARE(v.size(), 0);
-}
-
-void tst_QVector::eraseEmptyInt() const
-{
- eraseEmpty<int>();
-}
-
-void tst_QVector::eraseEmptyMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- eraseEmpty<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::eraseEmptyCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- eraseEmpty<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::eraseEmptyReserved() const
-{
- QVector<T> v;
- v.reserve(10);
- v.erase(v.begin(), v.end());
- QCOMPARE(v.size(), 0);
-}
-
-void tst_QVector::eraseEmptyReservedInt() const
-{
- eraseEmptyReserved<int>();
-}
-
-void tst_QVector::eraseEmptyReservedMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- eraseEmptyReserved<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::eraseEmptyReservedCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- eraseEmptyReserved<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-struct SharedVectorChecker
-{
- SharedVectorChecker(const QVector<T> &original, bool doCopyVector)
- : originalSize(-1),
- copy(0)
- {
- if (doCopyVector) {
- originalSize = original.size();
- copy = new QVector<T>(original);
- // this is unlikely to fail, but if the check in the destructor fails it's good to know that
- // we were still alright here.
- QCOMPARE(originalSize, copy->size());
- }
- }
-
- ~SharedVectorChecker()
- {
- if (copy)
- QCOMPARE(copy->size(), originalSize);
- delete copy;
- }
-
- int originalSize;
- QVector<T> *copy;
-};
-
-template<typename T>
-void tst_QVector::erase(bool shared) const
-{
- // note: remove() is actually more efficient, and more dangerous, because it uses the non-detaching
- // begin() / end() internally. you can also use constBegin() and constEnd() with erase(), but only
- // using reinterpret_cast... because both iterator types are really just pointers.
- // so we use a mix of erase() and remove() to cover more cases.
- {
- QVector<T> v = SimpleValue<T>::vector(12);
- SharedVectorChecker<T> svc(v, shared);
- v.erase(v.begin());
- QCOMPARE(v.size(), 11);
- for (int i = 0; i < 11; i++)
- QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
- v.erase(v.begin(), v.end());
- QCOMPARE(v.size(), 0);
- if (shared)
- QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
- }
- {
- QVector<T> v = SimpleValue<T>::vector(12);
- SharedVectorChecker<T> svc(v, shared);
- v.remove(1);
- QCOMPARE(v.size(), 11);
- QCOMPARE(v.at(0), SimpleValue<T>::at(0));
- for (int i = 1; i < 11; i++)
- QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
- v.erase(v.begin() + 1, v.end());
- QCOMPARE(v.size(), 1);
- QCOMPARE(v.at(0), SimpleValue<T>::at(0));
- if (shared)
- QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
- }
- {
- QVector<T> v = SimpleValue<T>::vector(12);
- SharedVectorChecker<T> svc(v, shared);
- v.erase(v.begin(), v.end() - 1);
- QCOMPARE(v.size(), 1);
- QCOMPARE(v.at(0), SimpleValue<T>::at(11));
- if (shared)
- QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
- }
- {
- QVector<T> v = SimpleValue<T>::vector(12);
- SharedVectorChecker<T> svc(v, shared);
- v.remove(5);
- QCOMPARE(v.size(), 11);
- for (int i = 0; i < 5; i++)
- QCOMPARE(v.at(i), SimpleValue<T>::at(i));
- for (int i = 5; i < 11; i++)
- QCOMPARE(v.at(i), SimpleValue<T>::at(i + 1));
- v.erase(v.begin() + 1, v.end() - 1);
- QCOMPARE(v.at(0), SimpleValue<T>::at(0));
- QCOMPARE(v.at(1), SimpleValue<T>::at(11));
- QCOMPARE(v.size(), 2);
- if (shared)
- QCOMPARE(SimpleValue<T>::vector(12), *svc.copy);
- }
-}
-
-void tst_QVector::eraseInt() const
-{
- erase<int>(false);
-}
-
-void tst_QVector::eraseIntShared() const
-{
- erase<int>(true);
-}
-
-void tst_QVector::eraseMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- erase<Movable>(false);
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::eraseMovableShared() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- erase<Movable>(true);
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::eraseCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- erase<Custom>(false);
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::eraseCustomShared() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- erase<Custom>(true);
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T> void tst_QVector::eraseReserved() const
-{
- {
- QVector<T> v(12);
- v.reserve(16);
- v.erase(v.begin());
- QCOMPARE(v.size(), 11);
- v.erase(v.begin(), v.end());
- QCOMPARE(v.size(), 0);
- }
- {
- QVector<T> v(12);
- v.reserve(16);
- v.erase(v.begin() + 1);
- QCOMPARE(v.size(), 11);
- v.erase(v.begin() + 1, v.end());
- QCOMPARE(v.size(), 1);
- }
- {
- QVector<T> v(12);
- v.reserve(16);
- v.erase(v.begin(), v.end() - 1);
- QCOMPARE(v.size(), 1);
- }
- {
- QVector<T> v(12);
- v.reserve(16);
- v.erase(v.begin() + 5);
- QCOMPARE(v.size(), 11);
- v.erase(v.begin() + 1, v.end() - 1);
- QCOMPARE(v.size(), 2);
- }
-}
-
-void tst_QVector::eraseReservedInt() const
-{
- eraseReserved<int>();
-}
-
-void tst_QVector::eraseReservedMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- eraseReserved<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::eraseReservedCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- eraseReserved<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::fill() const
-{
- QVector<T> myvec;
-
- // resize
- myvec.resize(5);
- myvec.fill(SimpleValue<T>::at(1));
- QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
- << SimpleValue<T>::at(1) << SimpleValue<T>::at(1)
- << SimpleValue<T>::at(1));
-
- // make sure it can resize itself too
- myvec.fill(SimpleValue<T>::at(2), 10);
- QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
- << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
- << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
- << SimpleValue<T>::at(2) << SimpleValue<T>::at(2)
- << SimpleValue<T>::at(2) << SimpleValue<T>::at(2));
-}
-
-void tst_QVector::fillInt() const
-{
- fill<int>();
-}
-
-void tst_QVector::fillMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- fill<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::fillCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- fill<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::fillDetaches() const
-{
- QVector<int> test = { 1, 2, 3 };
- QVector<int> copy = test;
- copy.fill(42);
-
- QCOMPARE(test, QVector<int>({1, 2, 3}));
- QCOMPARE(copy, QVector<int>({42, 42, 42}));
-}
-
-void tst_QVector::first() const
-{
- QVector<int> myvec;
- myvec << 69 << 42 << 3;
-
- // test it starts ok
- QCOMPARE(myvec.first(), 69);
- QCOMPARE(myvec.constFirst(), 69);
-
- // test removal changes
- myvec.remove(0);
- QCOMPARE(myvec.first(), 42);
- QCOMPARE(myvec.constFirst(), 42);
-
- // test prepend changes
- myvec.prepend(23);
- QCOMPARE(myvec.first(), 23);
- QCOMPARE(myvec.constFirst(), 23);
-}
-
-void tst_QVector::constFirst() const
-{
- QVector<int> myvec;
- myvec << 69 << 42 << 3;
-
- // test it starts ok
- QCOMPARE(myvec.constFirst(), 69);
- QVERIFY(myvec.isDetached());
-
- QVector<int> myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constFirst(), 69);
- QCOMPARE(myvecCopy.constFirst(), 69);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- // test removal changes
- myvec.remove(0);
- QVERIFY(myvec.isDetached());
- QVERIFY(!myvec.isSharedWith(myvecCopy));
- QCOMPARE(myvec.constFirst(), 42);
- QCOMPARE(myvecCopy.constFirst(), 69);
-
- myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constFirst(), 42);
- QCOMPARE(myvecCopy.constFirst(), 42);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- // test prepend changes
- myvec.prepend(23);
- QVERIFY(myvec.isDetached());
- QVERIFY(!myvec.isSharedWith(myvecCopy));
- QCOMPARE(myvec.constFirst(), 23);
- QCOMPARE(myvecCopy.constFirst(), 42);
-
- myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constFirst(), 23);
- QCOMPARE(myvecCopy.constFirst(), 23);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-}
-
-
-template<typename T>
-void tst_QVector::fromList() const
-{
- QList<T> list;
- list << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3);
-
- QVector<T> myvec;
- myvec = QVector<T>::fromList(list);
-
- // test it worked ok
- QCOMPARE(myvec, QVector<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
- QCOMPARE(list, QList<T>() << SimpleValue<T>::at(0) << SimpleValue<T>::at(1) << SimpleValue<T>::at(2) << SimpleValue<T>::at(3));
-}
-
-void tst_QVector::fromListInt() const
-{
- fromList<int>();
-}
-
-void tst_QVector::fromListMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- fromList<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::fromListCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- fromList<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-void tst_QVector::fromStdVector() const
-{
- // stl = :(
- std::vector<QString> svec;
- svec.push_back(QLatin1String("aaa"));
- svec.push_back(QLatin1String("bbb"));
- svec.push_back(QLatin1String("ninjas"));
- svec.push_back(QLatin1String("pirates"));
- QVector<QString> myvec = QVector<QString>::fromStdVector(svec);
-
- // test it converts ok
- QCOMPARE(myvec, QVector<QString>() << "aaa" << "bbb" << "ninjas" << "pirates");
-}
-#endif
-
-void tst_QVector::indexOf() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C" << "B" << "A";
-
- QVERIFY(myvec.indexOf("B") == 1);
- QVERIFY(myvec.indexOf("B", 1) == 1);
- QVERIFY(myvec.indexOf("B", 2) == 3);
- QVERIFY(myvec.indexOf("X") == -1);
- QVERIFY(myvec.indexOf("X", 2) == -1);
-
- // add an X
- myvec << "X";
- QVERIFY(myvec.indexOf("X") == 5);
- QVERIFY(myvec.indexOf("X", 5) == 5);
- QVERIFY(myvec.indexOf("X", 6) == -1);
-
- // remove first A
- myvec.remove(0);
- QVERIFY(myvec.indexOf("A") == 3);
- QVERIFY(myvec.indexOf("A", 3) == 3);
- QVERIFY(myvec.indexOf("A", 4) == -1);
-}
-
-template <typename T>
-void tst_QVector::insert() const
-{
- QVector<T> myvec;
- const T
- tA = SimpleValue<T>::at(0),
- tB = SimpleValue<T>::at(1),
- tC = SimpleValue<T>::at(2),
- tX = SimpleValue<T>::at(3),
- tZ = SimpleValue<T>::at(4),
- tT = SimpleValue<T>::at(5),
- ti = SimpleValue<T>::at(6);
- myvec << tA << tB << tC;
- QVector<T> myvec2 = myvec;
-
- // first position
- QCOMPARE(myvec.at(0), tA);
- myvec.insert(0, tX);
- QCOMPARE(myvec.at(0), tX);
- QCOMPARE(myvec.at(1), tA);
-
- QCOMPARE(myvec2.at(0), tA);
- myvec2.insert(myvec2.begin(), tX);
- QCOMPARE(myvec2.at(0), tX);
- QCOMPARE(myvec2.at(1), tA);
-
- // middle
- myvec.insert(1, tZ);
- QCOMPARE(myvec.at(0), tX);
- QCOMPARE(myvec.at(1), tZ);
- QCOMPARE(myvec.at(2), tA);
-
- myvec2.insert(myvec2.begin() + 1, tZ);
- QCOMPARE(myvec2.at(0), tX);
- QCOMPARE(myvec2.at(1), tZ);
- QCOMPARE(myvec2.at(2), tA);
-
- // end
- myvec.insert(5, tT);
- QCOMPARE(myvec.at(5), tT);
- QCOMPARE(myvec.at(4), tC);
-
- myvec2.insert(myvec2.end(), tT);
- QCOMPARE(myvec2.at(5), tT);
- QCOMPARE(myvec2.at(4), tC);
-
- // insert a lot of garbage in the middle
- myvec.insert(2, 2, ti);
- QCOMPARE(myvec, QVector<T>() << tX << tZ << ti << ti
- << tA << tB << tC << tT);
-
- myvec2.insert(myvec2.begin() + 2, 2, ti);
- QCOMPARE(myvec2, myvec);
-
- // insert from references to the same container:
- myvec.insert(0, 1, myvec[5]); // inserts tB
- myvec2.insert(0, 1, myvec2[5]); // inserts tB
- QCOMPARE(myvec, QVector<T>() << tB << tX << tZ << ti << ti
- << tA << tB << tC << tT);
- QCOMPARE(myvec2, myvec);
-
- myvec.insert(0, 1, const_cast<const QVector<T>&>(myvec)[0]); // inserts tB
- myvec2.insert(0, 1, const_cast<const QVector<T>&>(myvec2)[0]); // inserts tB
- QCOMPARE(myvec, QVector<T>() << tB << tB << tX << tZ << ti << ti
- << tA << tB << tC << tT);
- QCOMPARE(myvec2, myvec);
-}
-
-void tst_QVector::insertInt() const
-{
- insert<int>();
-}
-
-void tst_QVector::insertMovable() const
-{
- insert<Movable>();
-}
-
-void tst_QVector::insertCustom() const
-{
- insert<Custom>();
-}
-
-void tst_QVector::isEmpty() const
-{
- QVector<QString> myvec;
-
- // starts ok
- QVERIFY(myvec.isEmpty());
-
- // not empty now
- myvec.append(QLatin1String("hello there"));
- QVERIFY(!myvec.isEmpty());
-
- // empty again
- myvec.remove(0);
- QVERIFY(myvec.isEmpty());
-}
-
-void tst_QVector::last() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C";
-
- // test starts ok
- QCOMPARE(myvec.last(), QLatin1String("C"));
- QCOMPARE(myvec.constLast(), QLatin1String("C"));
-
- // test it changes ok
- myvec.append(QLatin1String("X"));
- QCOMPARE(myvec.last(), QLatin1String("X"));
- QCOMPARE(myvec.constLast(), QLatin1String("X"));
-
- // and remove again
- myvec.remove(3);
- QCOMPARE(myvec.last(), QLatin1String("C"));
- QCOMPARE(myvec.constLast(), QLatin1String("C"));
-}
-
-void tst_QVector::constLast() const
-{
- QVector<int> myvec;
- myvec << 69 << 42 << 3;
-
- // test it starts ok
- QCOMPARE(myvec.constLast(), 3);
- QVERIFY(myvec.isDetached());
-
- QVector<int> myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constLast(), 3);
- QCOMPARE(myvecCopy.constLast(), 3);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- // test removal changes
- myvec.removeLast();
- QVERIFY(myvec.isDetached());
- QVERIFY(!myvec.isSharedWith(myvecCopy));
- QCOMPARE(myvec.constLast(), 42);
- QCOMPARE(myvecCopy.constLast(), 3);
-
- myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constLast(), 42);
- QCOMPARE(myvecCopy.constLast(), 42);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- // test prepend changes
- myvec.append(23);
- QVERIFY(myvec.isDetached());
- QVERIFY(!myvec.isSharedWith(myvecCopy));
- QCOMPARE(myvec.constLast(), 23);
- QCOMPARE(myvecCopy.constLast(), 42);
-
- myvecCopy = myvec;
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-
- QCOMPARE(myvec.constLast(), 23);
- QCOMPARE(myvecCopy.constLast(), 23);
-
- QVERIFY(!myvec.isDetached());
- QVERIFY(!myvecCopy.isDetached());
- QVERIFY(myvec.isSharedWith(myvecCopy));
- QVERIFY(myvecCopy.isSharedWith(myvec));
-}
-
-void tst_QVector::lastIndexOf() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C" << "B" << "A";
-
- QVERIFY(myvec.lastIndexOf("B") == 3);
- QVERIFY(myvec.lastIndexOf("B", 2) == 1);
- QVERIFY(myvec.lastIndexOf("X") == -1);
- QVERIFY(myvec.lastIndexOf("X", 2) == -1);
-
- // add an X
- myvec << "X";
- QVERIFY(myvec.lastIndexOf("X") == 5);
- QVERIFY(myvec.lastIndexOf("X", 5) == 5);
- QVERIFY(myvec.lastIndexOf("X", 3) == -1);
-
- // remove first A
- myvec.remove(0);
- QVERIFY(myvec.lastIndexOf("A") == 3);
- QVERIFY(myvec.lastIndexOf("A", 3) == 3);
- QVERIFY(myvec.lastIndexOf("A", 2) == -1);
-}
-
-void tst_QVector::mid() const
-{
- QVector<QString> list;
- list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty";
-
- QCOMPARE(list.mid(3, 3), QVector<QString>() << "bak" << "buck" << "hello");
- QCOMPARE(list.mid(6, 10), QVector<QString>() << "kitty");
- QCOMPARE(list.mid(-1, 20), list);
- QCOMPARE(list.mid(4), QVector<QString>() << "buck" << "hello" << "kitty");
-}
-
-template <typename T>
-void tst_QVector::qhash() const
-{
- QVector<T> l1, l2;
- QCOMPARE(qHash(l1), qHash(l2));
- l1 << SimpleValue<T>::at(0);
- l2 << SimpleValue<T>::at(0);
- QCOMPARE(qHash(l1), qHash(l2));
-}
-
-template <typename T>
-void tst_QVector::move() const
-{
- QVector<T> list;
- list << T_FOO << T_BAR << T_BAZ;
-
- // move an item
- list.move(0, list.count() - 1);
- QCOMPARE(list, QVector<T>() << T_BAR << T_BAZ << T_FOO);
-
- // move it back
- list.move(list.count() - 1, 0);
- QCOMPARE(list, QVector<T>() << T_FOO << T_BAR << T_BAZ);
-
- // move an item in the middle
- list.move(1, 0);
- QCOMPARE(list, QVector<T>() << T_BAR << T_FOO << T_BAZ);
-}
-
-void tst_QVector::moveInt() const
-{
- move<int>();
-}
-
-void tst_QVector::moveMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- move<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::moveCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- move<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-template<typename T>
-void tst_QVector::prepend() const
-{
- QVector<T> myvec;
- T val1 = SimpleValue<T>::at(0);
- T val2 = SimpleValue<T>::at(1);
- T val3 = SimpleValue<T>::at(2);
- T val4 = SimpleValue<T>::at(3);
- T val5 = SimpleValue<T>::at(4);
- myvec << val1 << val2 << val3;
-
- // starts ok
- QVERIFY(myvec.size() == 3);
- QCOMPARE(myvec.at(0), val1);
-
- // add something
- myvec.prepend(val4);
- QCOMPARE(myvec.at(0), val4);
- QCOMPARE(myvec.at(1), val1);
- QVERIFY(myvec.size() == 4);
-
- // something else
- myvec.prepend(val5);
- QCOMPARE(myvec.at(0), val5);
- QCOMPARE(myvec.at(1), val4);
- QCOMPARE(myvec.at(2), val1);
- QVERIFY(myvec.size() == 5);
-
- // clear and prepend to an empty vector
- myvec.clear();
- QVERIFY(myvec.size() == 0);
- myvec.prepend(val5);
- QVERIFY(myvec.size() == 1);
- QCOMPARE(myvec.at(0), val5);
-}
-
-void tst_QVector::prependInt() const
-{
- prepend<int>();
-}
-
-void tst_QVector::prependMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- prepend<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::prependCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- prepend<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::removeAllWithAlias() const
-{
- QVector<QString> strings;
- strings << "One" << "Two" << "Three" << "One" /* must be distinct, but equal */;
- QCOMPARE(strings.removeAll(strings.front()), 2); // will trigger asan/ubsan
-}
-
-template<typename T>
-void tst_QVector::remove() const
-{
- QVector<T> myvec;
- T val1 = SimpleValue<T>::at(1);
- T val2 = SimpleValue<T>::at(2);
- T val3 = SimpleValue<T>::at(3);
- T val4 = SimpleValue<T>::at(4);
- myvec << val1 << val2 << val3;
- myvec << val1 << val2 << val3;
- myvec << val1 << val2 << val3;
- // remove middle
- myvec.remove(1);
- QCOMPARE(myvec, QVector<T>() << val1 << val3 << val1 << val2 << val3 << val1 << val2 << val3);
-
- // removeOne()
- QVERIFY(!myvec.removeOne(val4));
- QVERIFY(myvec.removeOne(val2));
- QCOMPARE(myvec, QVector<T>() << val1 << val3 << val1 << val3 << val1 << val2 << val3);
-
- QVector<T> myvecCopy = myvec;
- QVERIFY(myvecCopy.isSharedWith(myvec));
- // removeAll()
- QCOMPARE(myvec.removeAll(val4), 0);
- QVERIFY(myvecCopy.isSharedWith(myvec));
- QCOMPARE(myvec.removeAll(val1), 3);
- QVERIFY(!myvecCopy.isSharedWith(myvec));
- QCOMPARE(myvec, QVector<T>() << val3 << val3 << val2 << val3);
- myvecCopy = myvec;
- QVERIFY(myvecCopy.isSharedWith(myvec));
- QCOMPARE(myvec.removeAll(val2), 1);
- QVERIFY(!myvecCopy.isSharedWith(myvec));
- QCOMPARE(myvec, QVector<T>() << val3 << val3 << val3);
-
- // remove rest
- myvec.remove(0, 3);
- QCOMPARE(myvec, QVector<T>());
-}
-
-void tst_QVector::removeInt() const
-{
- remove<int>();
-}
-
-void tst_QVector::removeMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- remove<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::removeCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- remove<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-struct RemoveLastTestClass
-{
- RemoveLastTestClass() { other = 0; deleted = false; }
- RemoveLastTestClass *other;
- bool deleted;
- ~RemoveLastTestClass()
- {
- deleted = true;
- if (other)
- other->other = 0;
- }
-};
-
-void tst_QVector::removeFirstLast() const
-{
- // pop_pack - pop_front
- QVector<int> t, t2;
- t.append(1);
- t.append(2);
- t.append(3);
- t.append(4);
- t2 = t;
- t.pop_front();
- QCOMPARE(t.size(), 3);
- QCOMPARE(t.at(0), 2);
- t.pop_back();
- QCOMPARE(t.size(), 2);
- QCOMPARE(t.at(0), 2);
- QCOMPARE(t.at(1), 3);
-
- // takefirst - takeLast
- int n1 = t2.takeLast();
- QCOMPARE(t2.size(), 3);
- QCOMPARE(n1, 4);
- QCOMPARE(t2.at(0), 1);
- QCOMPARE(t2.at(2), 3);
- n1 = t2.takeFirst();
- QCOMPARE(t2.size(), 2);
- QCOMPARE(n1, 1);
- QCOMPARE(t2.at(0), 2);
- QCOMPARE(t2.at(1), 3);
-
- // remove first
- QVector<int> x, y;
- x.append(1);
- x.append(2);
- y = x;
- x.removeFirst();
- QCOMPARE(x.size(), 1);
- QCOMPARE(y.size(), 2);
- QCOMPARE(x.at(0), 2);
-
- // remove Last
- QVector<RemoveLastTestClass> v;
- v.resize(2);
- v[0].other = &(v[1]);
- v[1].other = &(v[0]);
- // Check dtor - complex type
- QVERIFY(v.at(0).other != 0);
- v.removeLast();
- QVERIFY(v.at(0).other == 0);
- QCOMPARE(v.at(0).deleted, false);
- // check iterator
- int count = 0;
- for (QVector<RemoveLastTestClass>::const_iterator i = v.constBegin(); i != v.constEnd(); ++i) {
- ++count;
- QVERIFY(i->other == 0);
- QCOMPARE(i->deleted, false);
- }
- // Check size
- QCOMPARE(count, 1);
- QCOMPARE(v.size(), 1);
- v.removeLast();
- QCOMPARE(v.size(), 0);
- // Check if we do correct realloc
- QVector<int> v2, v3;
- v2.append(1);
- v2.append(2);
- v3 = v2; // shared
- v2.removeLast();
- QCOMPARE(v2.size(), 1);
- QCOMPARE(v3.size(), 2);
- QCOMPARE(v2.at(0), 1);
- QCOMPARE(v3.at(0), 1);
- QCOMPARE(v3.at(1), 2);
-
- // Remove last with shared
- QVector<int> z1, z2;
- z1.append(9);
- z2 = z1;
- z1.removeLast();
- QCOMPARE(z1.size(), 0);
- QCOMPARE(z2.size(), 1);
- QCOMPARE(z2.at(0), 9);
-}
-
-
-void tst_QVector::resizePOD_data() const
-{
- QTest::addColumn<QVector<int> >("vector");
- QTest::addColumn<int>("size");
-
- QVERIFY(!QTypeInfo<int>::isComplex);
- QVERIFY(!QTypeInfo<int>::isStatic);
-
- QVector<int> null;
- QVector<int> empty(0, 5);
- QVector<int> emptyReserved;
- QVector<int> nonEmpty;
- QVector<int> nonEmptyReserved;
-
- emptyReserved.reserve(10);
- nonEmptyReserved.reserve(15);
- nonEmpty << 0 << 1 << 2 << 3 << 4;
- nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6;
- QVERIFY(emptyReserved.capacity() >= 10);
- QVERIFY(nonEmptyReserved.capacity() >= 15);
-
- QTest::newRow("null") << null << 10;
- QTest::newRow("empty") << empty << 10;
- QTest::newRow("emptyReserved") << emptyReserved << 10;
- QTest::newRow("nonEmpty") << nonEmpty << 10;
- QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
-}
-
-void tst_QVector::resizePOD() const
-{
- QFETCH(QVector<int>, vector);
- QFETCH(int, size);
-
- const int oldSize = vector.size();
-
- vector.resize(size);
- QCOMPARE(vector.size(), size);
- QVERIFY(vector.capacity() >= size);
- for (int i = oldSize; i < size; ++i)
- QVERIFY(vector[i] == 0); // check initialization
-
- const int capacity = vector.capacity();
-
- vector.clear();
- QCOMPARE(vector.size(), 0);
- QVERIFY(vector.capacity() <= capacity);
-}
-
-void tst_QVector::resizeComplexMovable_data() const
-{
- QTest::addColumn<QVector<Movable> >("vector");
- QTest::addColumn<int>("size");
-
- QVERIFY(QTypeInfo<Movable>::isComplex);
- QVERIFY(!QTypeInfo<Movable>::isStatic);
-
- QVector<Movable> null;
- QVector<Movable> empty(0, 'Q');
- QVector<Movable> emptyReserved;
- QVector<Movable> nonEmpty;
- QVector<Movable> nonEmptyReserved;
-
- emptyReserved.reserve(10);
- nonEmptyReserved.reserve(15);
- nonEmpty << '0' << '1' << '2' << '3' << '4';
- nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
- QVERIFY(emptyReserved.capacity() >= 10);
- QVERIFY(nonEmptyReserved.capacity() >= 15);
-
- QTest::newRow("null") << null << 10;
- QTest::newRow("empty") << empty << 10;
- QTest::newRow("emptyReserved") << emptyReserved << 10;
- QTest::newRow("nonEmpty") << nonEmpty << 10;
- QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
-}
-
-void tst_QVector::resizeComplexMovable() const
-{
- const int items = Movable::counter.loadAcquire();
- {
- QFETCH(QVector<Movable>, vector);
- QFETCH(int, size);
-
- const int oldSize = vector.size();
-
- vector.resize(size);
- QCOMPARE(vector.size(), size);
- QVERIFY(vector.capacity() >= size);
- for (int i = oldSize; i < size; ++i)
- QVERIFY(vector[i] == 'j'); // check initialization
-
- const int capacity = vector.capacity();
-
- vector.resize(0);
- QCOMPARE(vector.size(), 0);
- QVERIFY(vector.capacity() <= capacity);
- }
- QCOMPARE(items, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::resizeComplex_data() const
-{
- QTest::addColumn<QVector<Custom> >("vector");
- QTest::addColumn<int>("size");
-
- QVERIFY(QTypeInfo<Custom>::isComplex);
- QVERIFY(QTypeInfo<Custom>::isStatic);
-
- QVector<Custom> null;
- QVector<Custom> empty(0, '0');
- QVector<Custom> emptyReserved;
- QVector<Custom> nonEmpty;
- QVector<Custom> nonEmptyReserved;
-
- emptyReserved.reserve(10);
- nonEmptyReserved.reserve(15);
- nonEmpty << '0' << '1' << '2' << '3' << '4';
- nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
- QVERIFY(emptyReserved.capacity() >= 10);
- QVERIFY(nonEmptyReserved.capacity() >= 15);
-
- QTest::newRow("null") << null << 10;
- QTest::newRow("empty") << empty << 10;
- QTest::newRow("emptyReserved") << emptyReserved << 10;
- QTest::newRow("nonEmpty") << nonEmpty << 10;
- QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10;
-}
-
-void tst_QVector::resizeComplex() const
-{
- const int items = Custom::counter.loadAcquire();
- {
- QFETCH(QVector<Custom>, vector);
- QFETCH(int, size);
-
- int oldSize = vector.size();
- vector.resize(size);
- QCOMPARE(vector.size(), size);
- QVERIFY(vector.capacity() >= size);
- for (int i = oldSize; i < size; ++i)
- QVERIFY(vector[i].i == 'j'); // check default initialization
-
- const int capacity = vector.capacity();
-
- vector.resize(0);
- QCOMPARE(vector.size(), 0);
- QVERIFY(vector.isEmpty());
- QVERIFY(vector.capacity() <= capacity);
- }
- QCOMPARE(Custom::counter.loadAcquire(), items);
-}
-
-void tst_QVector::resizeCtorAndDtor() const
-{
- const int items = Custom::counter.loadAcquire();
- {
- QVector<Custom> null;
- QVector<Custom> empty(0, '0');
- QVector<Custom> emptyReserved;
- QVector<Custom> nonEmpty;
- QVector<Custom> nonEmptyReserved;
-
- emptyReserved.reserve(10);
- nonEmptyReserved.reserve(15);
- nonEmpty << '0' << '1' << '2' << '3' << '4';
- nonEmptyReserved << '0' << '1' << '2' << '3' << '4' << '5' << '6';
- QVERIFY(emptyReserved.capacity() >= 10);
- QVERIFY(nonEmptyReserved.capacity() >= 15);
-
- // start playing with vectors
- null.resize(21);
- nonEmpty.resize(2);
- emptyReserved.resize(0);
- nonEmpty.resize(0);
- nonEmptyReserved.resize(2);
- }
- QCOMPARE(Custom::counter.loadAcquire(), items);
-}
-
-void tst_QVector::reverseIterators() const
-{
- QVector<int> v;
- v << 1 << 2 << 3 << 4;
- QVector<int> vr = v;
- std::reverse(vr.begin(), vr.end());
- const QVector<int> &cvr = vr;
- QVERIFY(std::equal(v.begin(), v.end(), vr.rbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), vr.crbegin()));
- QVERIFY(std::equal(v.begin(), v.end(), cvr.rbegin()));
- QVERIFY(std::equal(vr.rbegin(), vr.rend(), v.begin()));
- QVERIFY(std::equal(vr.crbegin(), vr.crend(), v.begin()));
- QVERIFY(std::equal(cvr.rbegin(), cvr.rend(), v.begin()));
-}
-
-template<typename T>
-void tst_QVector::size() const
-{
- // zero size
- QVector<T> myvec;
- QVERIFY(myvec.size() == 0);
-
- // grow
- myvec.append(SimpleValue<T>::at(0));
- QVERIFY(myvec.size() == 1);
- myvec.append(SimpleValue<T>::at(1));
- QVERIFY(myvec.size() == 2);
-
- // shrink
- myvec.remove(0);
- QVERIFY(myvec.size() == 1);
- myvec.remove(0);
- QVERIFY(myvec.size() == 0);
-}
-
-void tst_QVector::sizeInt() const
-{
- size<int>();
-}
-
-void tst_QVector::sizeMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- size<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::sizeCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- size<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-// ::squeeze() is tested in ::capacity().
-
-void tst_QVector::startsWith() const
-{
- QVector<int> myvec;
-
- // empty vector
- QVERIFY(!myvec.startsWith(1));
-
- // add the one, should work
- myvec.prepend(1);
- QVERIFY(myvec.startsWith(1));
-
- // add something else, fails now
- myvec.prepend(3);
- QVERIFY(!myvec.startsWith(1));
-
- // remove it again :)
- myvec.remove(0);
- QVERIFY(myvec.startsWith(1));
-}
-
-template<typename T>
-void tst_QVector::swap() const
-{
- QVector<T> v1, v2;
- T val1 = SimpleValue<T>::at(0);
- T val2 = SimpleValue<T>::at(1);
- T val3 = SimpleValue<T>::at(2);
- T val4 = SimpleValue<T>::at(3);
- T val5 = SimpleValue<T>::at(4);
- T val6 = SimpleValue<T>::at(5);
- v1 << val1 << val2 << val3;
- v2 << val4 << val5 << val6;
-
- v1.swap(v2);
- QCOMPARE(v1,QVector<T>() << val4 << val5 << val6);
- QCOMPARE(v2,QVector<T>() << val1 << val2 << val3);
-}
-
-void tst_QVector::swapInt() const
-{
- swap<int>();
-}
-
-void tst_QVector::swapMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- swap<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::swapCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- swap<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::toList() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C";
-
- // make sure it converts and doesn't modify the original vector
- QCOMPARE(myvec.toList(), QList<QString>() << "A" << "B" << "C");
- QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C");
-}
-
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-void tst_QVector::toStdVector() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C";
-
- std::vector<QString> svec = myvec.toStdVector();
- QCOMPARE(svec.at(0), QLatin1String("A"));
- QCOMPARE(svec.at(1), QLatin1String("B"));
- QCOMPARE(svec.at(2), QLatin1String("C"));
-
- QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C");
-}
-#endif
-
-void tst_QVector::value() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C";
-
- // valid calls
- QCOMPARE(myvec.value(0), QLatin1String("A"));
- QCOMPARE(myvec.value(1), QLatin1String("B"));
- QCOMPARE(myvec.value(2), QLatin1String("C"));
-
- // default calls
- QCOMPARE(myvec.value(-1), QString());
- QCOMPARE(myvec.value(3), QString());
-
- // test calls with a provided default, valid calls
- QCOMPARE(myvec.value(0, QLatin1String("default")), QLatin1String("A"));
- QCOMPARE(myvec.value(1, QLatin1String("default")), QLatin1String("B"));
- QCOMPARE(myvec.value(2, QLatin1String("default")), QLatin1String("C"));
-
- // test calls with a provided default that will return the default
- QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default"));
- QCOMPARE(myvec.value(3, QLatin1String("default")), QLatin1String("default"));
-}
-
-void tst_QVector::testOperators() const
-{
- QVector<QString> myvec;
- myvec << "A" << "B" << "C";
- QVector<QString> myvectwo;
- myvectwo << "D" << "E" << "F";
- QVector<QString> combined;
- combined << "A" << "B" << "C" << "D" << "E" << "F";
-
- // !=
- QVERIFY(myvec != myvectwo);
-
- // +
- QCOMPARE(myvec + myvectwo, combined);
- QCOMPARE(myvec, QVector<QString>() << "A" << "B" << "C");
- QCOMPARE(myvectwo, QVector<QString>() << "D" << "E" << "F");
-
- // +=
- myvec += myvectwo;
- QCOMPARE(myvec, combined);
-
- // ==
- QVERIFY(myvec == combined);
-
- // <, >, <=, >=
- QVERIFY(!(myvec < combined));
- QVERIFY(!(myvec > combined));
- QVERIFY( myvec <= combined);
- QVERIFY( myvec >= combined);
- combined.push_back("G");
- QVERIFY( myvec < combined);
- QVERIFY(!(myvec > combined));
- QVERIFY( myvec <= combined);
- QVERIFY(!(myvec >= combined));
- QVERIFY(combined > myvec);
- QVERIFY(combined >= myvec);
-
- // []
- QCOMPARE(myvec[0], QLatin1String("A"));
- QCOMPARE(myvec[1], QLatin1String("B"));
- QCOMPARE(myvec[2], QLatin1String("C"));
- QCOMPARE(myvec[3], QLatin1String("D"));
- QCOMPARE(myvec[4], QLatin1String("E"));
- QCOMPARE(myvec[5], QLatin1String("F"));
-}
-
-
-int fooCtor;
-int fooDtor;
-
-struct Foo
-{
- int *p;
-
- Foo() { p = new int; ++fooCtor; }
- Foo(const Foo &other) { Q_UNUSED(other); p = new int; ++fooCtor; }
-
- void operator=(const Foo & /* other */) { }
-
- ~Foo() { delete p; ++fooDtor; }
-};
-
-void tst_QVector::reserve()
-{
- fooCtor = 0;
- fooDtor = 0;
- {
- QVector<Foo> a;
- a.resize(2);
- QCOMPARE(fooCtor, 2);
- QVector<Foo> b(a);
- b.reserve(1);
- QCOMPARE(b.size(), a.size());
- QCOMPARE(fooDtor, 0);
- }
- QCOMPARE(fooCtor, fooDtor);
-}
-
-// This is a regression test for QTBUG-51758
-void tst_QVector::reserveZero()
-{
- QVector<int> vec;
- vec.detach();
- vec.reserve(0); // should not crash
- QCOMPARE(vec.size(), 0);
- QCOMPARE(vec.capacity(), 0);
- vec.squeeze();
- QCOMPARE(vec.size(), 0);
- QCOMPARE(vec.capacity(), 0);
- vec.reserve(-1);
- QCOMPARE(vec.size(), 0);
- QCOMPARE(vec.capacity(), 0);
- vec.append(42);
- QCOMPARE(vec.size(), 1);
- QVERIFY(vec.capacity() >= 1);
-}
-
-template<typename T>
-void tst_QVector::initializeList()
-{
- T val1(SimpleValue<T>::at(1));
- T val2(SimpleValue<T>::at(2));
- T val3(SimpleValue<T>::at(3));
- T val4(SimpleValue<T>::at(4));
-
- QVector<T> v1 {val1, val2, val3};
- QCOMPARE(v1, QVector<T>() << val1 << val2 << val3);
- QCOMPARE(v1, (QVector<T> {val1, val2, val3}));
-
- QVector<QVector<T>> v2{ v1, {val4}, QVector<T>(), {val1, val2, val3} };
- QVector<QVector<T>> v3;
- v3 << v1 << (QVector<T>() << val4) << QVector<T>() << v1;
- QCOMPARE(v3, v2);
-
- QVector<T> v4({});
- QCOMPARE(v4.size(), 0);
-}
-
-void tst_QVector::initializeListInt()
-{
- initializeList<int>();
-}
-
-void tst_QVector::initializeListMovable()
-{
- const int instancesCount = Movable::counter.loadAcquire();
- initializeList<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::initializeListCustom()
-{
- const int instancesCount = Custom::counter.loadAcquire();
- initializeList<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-void tst_QVector::const_shared_null()
-{
- QVector<int> v2;
- QVERIFY(!v2.isDetached());
-}
-
-template<typename T>
-void tst_QVector::detach() const
-{
- {
- // detach an empty vector
- QVector<T> v;
- v.detach();
- QVERIFY(!v.isDetached());
- QCOMPARE(v.size(), 0);
- QCOMPARE(v.capacity(), 0);
- }
- {
- // detach an empty referenced vector
- QVector<T> v;
- QVector<T> ref(v);
- QVERIFY(!v.isDetached());
- v.detach();
- QVERIFY(!v.isDetached());
- QCOMPARE(v.size(), 0);
- QCOMPARE(v.capacity(), 0);
- }
- {
- // detach a not empty referenced vector
- QVector<T> v(31);
- QVector<T> ref(v);
- QVERIFY(!v.isDetached());
- v.detach();
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 31);
- QCOMPARE(v.capacity(), 31);
- }
- {
- // detach a not empty vector
- QVector<T> v(31);
- QVERIFY(v.isDetached());
- v.detach(); // detaching a detached vector
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 31);
- QCOMPARE(v.capacity(), 31);
- }
- {
- // detach a not empty vector with preallocated space
- QVector<T> v(3);
- v.reserve(8);
- QVector<T> ref(v);
- QVERIFY(!v.isDetached());
- v.detach();
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 3);
- QCOMPARE(v.capacity(), 8);
- }
- {
- // detach a not empty vector with preallocated space
- QVector<T> v(3);
- v.reserve(8);
- QVERIFY(v.isDetached());
- v.detach(); // detaching a detached vector
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 3);
- QCOMPARE(v.capacity(), 8);
- }
- {
- // detach a not empty, initialized vector
- QVector<T> v(7, SimpleValue<T>::at(1));
- QVector<T> ref(v);
- QVERIFY(!v.isDetached());
- v.detach();
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 7);
- for (int i = 0; i < v.size(); ++i)
- QCOMPARE(v[i], SimpleValue<T>::at(1));
- }
- {
- // detach a not empty, initialized vector
- QVector<T> v(7, SimpleValue<T>::at(2));
- QVERIFY(v.isDetached());
- v.detach(); // detaching a detached vector
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 7);
- for (int i = 0; i < v.size(); ++i)
- QCOMPARE(v[i], SimpleValue<T>::at(2));
- }
- {
- // detach a not empty, initialized vector with preallocated space
- QVector<T> v(7, SimpleValue<T>::at(3));
- v.reserve(31);
- QVector<T> ref(v);
- QVERIFY(!v.isDetached());
- v.detach();
- QVERIFY(v.isDetached());
- QCOMPARE(v.size(), 7);
- QCOMPARE(v.capacity(), 31);
- for (int i = 0; i < v.size(); ++i)
- QCOMPARE(v[i], SimpleValue<T>::at(3));
- }
-}
-
-void tst_QVector::detachInt() const
-{
- detach<int>();
-}
-
-void tst_QVector::detachMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- detach<Movable>();
- QCOMPARE(instancesCount, Movable::counter.loadAcquire());
-}
-
-void tst_QVector::detachCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- detach<Custom>();
- QCOMPARE(instancesCount, Custom::counter.loadAcquire());
-}
-
-static QAtomicPointer<QVector<int> > detachThreadSafetyDataInt;
-static QAtomicPointer<QVector<Movable> > detachThreadSafetyDataMovable;
-static QAtomicPointer<QVector<Custom> > detachThreadSafetyDataCustom;
-
-template<typename T> QAtomicPointer<QVector<T> > *detachThreadSafetyData();
-template<> QAtomicPointer<QVector<int> > *detachThreadSafetyData() { return &detachThreadSafetyDataInt; }
-template<> QAtomicPointer<QVector<Movable> > *detachThreadSafetyData() { return &detachThreadSafetyDataMovable; }
-template<> QAtomicPointer<QVector<Custom> > *detachThreadSafetyData() { return &detachThreadSafetyDataCustom; }
-
-static QSemaphore detachThreadSafetyLock;
-
-template<typename T>
-void tst_QVector::detachThreadSafety() const
-{
- delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(new QVector<T>(SimpleValue<T>::vector(400)));
-
- static const uint threadsCount = 5;
-
- struct : QThread {
- void run() override
- {
- QVector<T> copy(*detachThreadSafetyData<T>()->loadRelaxed());
- QVERIFY(!copy.isDetached());
- detachThreadSafetyLock.release();
- detachThreadSafetyLock.acquire(100);
- copy.detach();
- }
- } threads[threadsCount];
-
- for (uint i = 0; i < threadsCount; ++i)
- threads[i].start();
- QThread::yieldCurrentThread();
- detachThreadSafetyLock.acquire(threadsCount);
-
- // destroy static original data
- delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(0);
-
- QVERIFY(threadsCount < 100);
- detachThreadSafetyLock.release(threadsCount * 100);
- QThread::yieldCurrentThread();
-
- for (uint i = 0; i < threadsCount; ++i)
- threads[i].wait();
-}
-
-void tst_QVector::detachThreadSafetyInt() const
-{
- for (uint i = 0; i < 128; ++i)
- detachThreadSafety<int>();
-}
-
-void tst_QVector::detachThreadSafetyMovable() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- for (uint i = 0; i < 128; ++i) {
- detachThreadSafety<Movable>();
- QCOMPARE(Movable::counter.loadAcquire(), instancesCount);
- }
-}
-
-void tst_QVector::detachThreadSafetyCustom() const
-{
- const int instancesCount = Custom::counter.loadAcquire();
- for (uint i = 0; i < 128; ++i) {
- detachThreadSafety<Custom>();
- QCOMPARE(Custom::counter.loadAcquire(), instancesCount);
- }
-}
-
-void tst_QVector::insertMove() const
-{
- const int instancesCount = Movable::counter.loadAcquire();
- {
- QVector<Movable> vec;
- vec.reserve(7);
- Movable m0;
- Movable m1;
- Movable m2;
- Movable m3;
- Movable m4;
- Movable m5;
- Movable m6;
-
- vec.append(std::move(m3));
- QVERIFY(m3.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m3));
- vec.push_back(std::move(m4));
- QVERIFY(m4.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m3));
- QVERIFY(vec.at(1).wasConstructedAt(&m4));
- vec.prepend(std::move(m1));
- QVERIFY(m1.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m1));
- QVERIFY(vec.at(1).wasConstructedAt(&m3));
- QVERIFY(vec.at(2).wasConstructedAt(&m4));
- vec.insert(1, std::move(m2));
- QVERIFY(m2.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m1));
- QVERIFY(vec.at(1).wasConstructedAt(&m2));
- QVERIFY(vec.at(2).wasConstructedAt(&m3));
- QVERIFY(vec.at(3).wasConstructedAt(&m4));
- vec += std::move(m5);
- QVERIFY(m5.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m1));
- QVERIFY(vec.at(1).wasConstructedAt(&m2));
- QVERIFY(vec.at(2).wasConstructedAt(&m3));
- QVERIFY(vec.at(3).wasConstructedAt(&m4));
- QVERIFY(vec.at(4).wasConstructedAt(&m5));
- vec << std::move(m6);
- QVERIFY(m6.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m1));
- QVERIFY(vec.at(1).wasConstructedAt(&m2));
- QVERIFY(vec.at(2).wasConstructedAt(&m3));
- QVERIFY(vec.at(3).wasConstructedAt(&m4));
- QVERIFY(vec.at(4).wasConstructedAt(&m5));
- QVERIFY(vec.at(5).wasConstructedAt(&m6));
- vec.push_front(std::move(m0));
- QVERIFY(m0.wasConstructedAt(nullptr));
- QVERIFY(vec.at(0).wasConstructedAt(&m0));
- QVERIFY(vec.at(1).wasConstructedAt(&m1));
- QVERIFY(vec.at(2).wasConstructedAt(&m2));
- QVERIFY(vec.at(3).wasConstructedAt(&m3));
- QVERIFY(vec.at(4).wasConstructedAt(&m4));
- QVERIFY(vec.at(5).wasConstructedAt(&m5));
- QVERIFY(vec.at(6).wasConstructedAt(&m6));
-
- QCOMPARE(Movable::counter.loadAcquire(), instancesCount + 14);
- }
- QCOMPARE(Movable::counter.loadAcquire(), instancesCount);
-}
-
-void tst_QVector::swapItemsAt() const
-{
- QVector<int> v;
- v << 0 << 1 << 2 << 3;
-
- v.swapItemsAt(0, 2);
- QCOMPARE(v.at(0), 2);
- QCOMPARE(v.at(2), 0);
-
- auto copy = v;
- copy.swapItemsAt(0, 2);
- QCOMPARE(v.at(0), 2);
- QCOMPARE(v.at(2), 0);
- QCOMPARE(copy.at(0), 0);
- QCOMPARE(copy.at(2), 2);
-}
-
-QTEST_MAIN(tst_QVector)
-#include "tst_qvector.moc"
diff --git a/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt b/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt
new file mode 100644
index 0000000000..8f6ed66841
--- /dev/null
+++ b/tests/auto/corelib/tools/qversionnumber/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qversionnumber Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qversionnumber LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qversionnumber
+ SOURCES
+ tst_qversionnumber.cpp
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro b/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro
deleted file mode 100644
index e2ae91cb64..0000000000
--- a/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-CONFIG += testcase
-qtConfig(c++11): CONFIG += c++11
-qtConfig(c++14): CONFIG += c++14
-TARGET = tst_qversionnumber
-QT = core testlib
-SOURCES = tst_qversionnumber.cpp
diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
index 7c4d1071ce..da9dcc9366 100644
--- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
+++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
@@ -1,33 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.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>
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
#include <QtCore/qversionnumber.h>
#include <QtCore/qlibraryinfo.h>
@@ -73,10 +48,15 @@ private slots:
void assignment();
void fromString_data();
void fromString();
+ void fromString_extra();
void toString_data();
void toString();
void isNull_data();
void isNull();
+ void iterators_data();
+ void iterators();
+ void iteratorsAreDefaultConstructible();
+ void valueInitializedIteratorsCompareEqual();
void serialize_data();
void serialize();
void moveSemantics();
@@ -85,56 +65,56 @@ private slots:
void tst_QVersionNumber::singleInstanceData()
{
- QTest::addColumn<QVector<int> >("segments");
+ QTest::addColumn<QList<int>>("segments");
QTest::addColumn<QVersionNumber>("expectedVersion");
QTest::addColumn<QString>("expectedString");
QTest::addColumn<QString>("constructionString");
QTest::addColumn<int>("suffixIndex");
QTest::addColumn<bool>("isNull");
- // segments expectedVersion expectedString constructionString suffixIndex null
- QTest::newRow("null") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QString() << 0 << true;
- QTest::newRow("text") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral("text") << 0 << true;
- QTest::newRow(" text") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral(" text") << 0 << true;
- QTest::newRow("Empty String") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral("Empty String") << 0 << true;
- QTest::newRow("-1.-2") << (QVector<int>()) << QVersionNumber() << QStringLiteral("") << QStringLiteral("-1.-2") << 0 << true;
- QTest::newRow("1.-2-3") << (QVector<int>() << 1) << QVersionNumber(QVector<int>() << 1) << QStringLiteral("1") << QStringLiteral("1.-2-3") << 1 << false;
- QTest::newRow("1.2-3") << (QVector<int>() << 1 << 2) << QVersionNumber(QVector<int>() << 1 << 2) << QStringLiteral("1.2") << QStringLiteral("1.2-3") << 3 << false;
- QTest::newRow("0") << (QVector<int>() << 0) << QVersionNumber(QVector<int>() << 0) << QStringLiteral("0") << QStringLiteral("0") << 1 << false;
- QTest::newRow("0.1") << (QVector<int>() << 0 << 1) << QVersionNumber(QVector<int>() << 0 << 1) << QStringLiteral("0.1") << QStringLiteral("0.1") << 3 << false;
- QTest::newRow("0.1.2") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2") << 5 << false;
- QTest::newRow("0.1.2alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2alpha") << 5 << false;
- QTest::newRow("0.1.2-alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2-alpha") << 5 << false;
- QTest::newRow("0.1.2.alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2.alpha") << 5 << false;
- QTest::newRow("0.1.2.3alpha") << (QVector<int>() << 0 << 1 << 2 << 3) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3) << QStringLiteral("0.1.2.3") << QStringLiteral("0.1.2.3alpha") << 7 << false;
- QTest::newRow("0.1.2.3.alpha") << (QVector<int>() << 0 << 1 << 2 << 3) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3) << QStringLiteral("0.1.2.3") << QStringLiteral("0.1.2.3.alpha") << 7 << false;
- QTest::newRow("0.1.2.3.4.alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4.alpha") << 9 << false;
- QTest::newRow("0.1.2.3.4 alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alpha") << 9 << false;
- QTest::newRow("0.1.2.3.4 alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alp ha") << 9 << false;
- QTest::newRow("0.1.2.3.4alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alp ha") << 9 << false;
- QTest::newRow("0.1.2.3.4alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alpha ") << 9 << false;
- QTest::newRow("0.1.2.3.4.5alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5) << QStringLiteral("0.1.2.3.4.5") << QStringLiteral("0.1.2.3.4.5alpha ") << 11 << false;
- QTest::newRow("0.1.2.3.4.5.6alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6) << QStringLiteral("0.1.2.3.4.5.6") << QStringLiteral("0.1.2.3.4.5.6alpha ") << 13 << false;
- QTest::newRow("0.1.2.3.4.5.6.7alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7) << QStringLiteral("0.1.2.3.4.5.6.7") << QStringLiteral("0.1.2.3.4.5.6.7alpha ") << 15 << false;
- QTest::newRow("0.1.2.3.4.5.6.7.8alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8alpha ") << 17 << false;
- QTest::newRow("0.1.2.3.4.5.6.7.8.alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8.alpha") << 17 << false;
- QTest::newRow("0.1.2.3.4.5.6.7.8 alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8 alpha") << 17 << false;
- QTest::newRow("0.1.2.3.4.5.6.7.8 alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8 alp ha") << 17 << false;
- QTest::newRow("0.1.2.3.4.5.6.7.8alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8alp ha") << 17 << false;
- QTest::newRow("10.09") << (QVector<int>() << 10 << 9) << QVersionNumber(QVector<int>() << 10 << 9) << QStringLiteral("10.9") << QStringLiteral("10.09") << 5 << false;
- QTest::newRow("10.0x") << (QVector<int>() << 10 << 0) << QVersionNumber(QVector<int>() << 10 << 0) << QStringLiteral("10.0") << QStringLiteral("10.0x") << 4 << false;
- QTest::newRow("10.0xTest") << (QVector<int>() << 10 << 0) << QVersionNumber(QVector<int>() << 10 << 0) << QStringLiteral("10.0") << QStringLiteral("10.0xTest") << 4 << false;
- QTest::newRow("127.09") << (QVector<int>() << 127 << 9) << QVersionNumber(QVector<int>() << 127 << 9) << QStringLiteral("127.9") << QStringLiteral("127.09") << 6 << false;
- QTest::newRow("127.0x") << (QVector<int>() << 127 << 0) << QVersionNumber(QVector<int>() << 127 << 0) << QStringLiteral("127.0") << QStringLiteral("127.0x") << 5 << false;
- QTest::newRow("127.0xTest") << (QVector<int>() << 127 << 0) << QVersionNumber(QVector<int>() << 127 << 0) << QStringLiteral("127.0") << QStringLiteral("127.0xTest") << 5 << false;
- QTest::newRow("128.09") << (QVector<int>() << 128 << 9) << QVersionNumber(QVector<int>() << 128 << 9) << QStringLiteral("128.9") << QStringLiteral("128.09") << 6 << false;
- QTest::newRow("128.0x") << (QVector<int>() << 128 << 0) << QVersionNumber(QVector<int>() << 128 << 0) << QStringLiteral("128.0") << QStringLiteral("128.0x") << 5 << false;
- QTest::newRow("128.0xTest") << (QVector<int>() << 128 << 0) << QVersionNumber(QVector<int>() << 128 << 0) << QStringLiteral("128.0") << QStringLiteral("128.0xTest") << 5 << false;
+ // segments expectedVersion expectedString constructionString suffixIndex null
+ QTest::newRow("null") << QList<int>() << QVersionNumber() << QString() << QString() << 0 << true;
+ QTest::newRow("text") << QList<int>() << QVersionNumber() << QString() << QStringLiteral("text") << 0 << true;
+ QTest::newRow(" text") << QList<int>() << QVersionNumber() << QString() << QStringLiteral(" text") << 0 << true;
+ QTest::newRow("Empty String") << QList<int>() << QVersionNumber() << QString() << QStringLiteral("Empty String") << 0 << true;
+ QTest::newRow("-1.-2") << QList<int>() << QVersionNumber() << QStringLiteral("") << QStringLiteral("-1.-2") << 0 << true;
+ QTest::newRow("1.-2-3") << QList<int> { 1 } << QVersionNumber(QList<int> { 1 }) << QStringLiteral("1") << QStringLiteral("1.-2-3") << 1 << false;
+ QTest::newRow("1.2-3") << QList<int> { 1, 2 } << QVersionNumber(QList<int> { 1, 2 }) << QStringLiteral("1.2") << QStringLiteral("1.2-3") << 3 << false;
+ QTest::newRow("0") << QList<int> { 0 } << QVersionNumber(QList<int> { 0 }) << QStringLiteral("0") << QStringLiteral("0") << 1 << false;
+ QTest::newRow("0.1") << QList<int> { 0, 1 } << QVersionNumber(QList<int> { 0, 1 }) << QStringLiteral("0.1") << QStringLiteral("0.1") << 3 << false;
+ QTest::newRow("0.1.2") << QList<int> { 0, 1, 2 } << QVersionNumber(QList<int> { 0, 1, 2 }) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2") << 5 << false;
+ QTest::newRow("0.1.2alpha") << QList<int> { 0, 1, 2 } << QVersionNumber(QList<int> { 0, 1, 2 }) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2alpha") << 5 << false;
+ QTest::newRow("0.1.2-alpha") << QList<int> { 0, 1, 2 } << QVersionNumber(QList<int> { 0, 1, 2 }) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2-alpha") << 5 << false;
+ QTest::newRow("0.1.2.alpha") << QList<int> { 0, 1, 2 } << QVersionNumber(QList<int> { 0, 1, 2 }) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2.alpha") << 5 << false;
+ QTest::newRow("0.1.2.3alpha") << QList<int> { 0, 1, 2, 3 } << QVersionNumber(QList<int> { 0, 1, 2, 3 }) << QStringLiteral("0.1.2.3") << QStringLiteral("0.1.2.3alpha") << 7 << false;
+ QTest::newRow("0.1.2.3.alpha") << QList<int> { 0, 1, 2, 3 } << QVersionNumber(QList<int> { 0, 1, 2, 3 }) << QStringLiteral("0.1.2.3") << QStringLiteral("0.1.2.3.alpha") << 7 << false;
+ QTest::newRow("0.1.2.3.4.alpha") << QList<int> { 0, 1, 2, 3, 4 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4 }) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4.alpha") << 9 << false;
+ QTest::newRow("0.1.2.3.4 alpha") << QList<int> { 0, 1, 2, 3, 4 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4 }) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alpha") << 9 << false;
+ QTest::newRow("0.1.2.3.4 alp ha") << QList<int> { 0, 1, 2, 3, 4 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4 }) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alp ha") << 9 << false;
+ QTest::newRow("0.1.2.3.4alp ha") << QList<int> { 0, 1, 2, 3, 4 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4 }) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alp ha") << 9 << false;
+ QTest::newRow("0.1.2.3.4alpha ") << QList<int> { 0, 1, 2, 3, 4 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4 }) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alpha ") << 9 << false;
+ QTest::newRow("0.1.2.3.4.5alpha ") << QList<int> { 0, 1, 2, 3, 4, 5 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5 }) << QStringLiteral("0.1.2.3.4.5") << QStringLiteral("0.1.2.3.4.5alpha ") << 11 << false;
+ QTest::newRow("0.1.2.3.4.5.6alpha ") << QList<int> { 0, 1, 2, 3, 4, 5, 6 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6 }) << QStringLiteral("0.1.2.3.4.5.6") << QStringLiteral("0.1.2.3.4.5.6alpha ") << 13 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7alpha ") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7 }) << QStringLiteral("0.1.2.3.4.5.6.7") << QStringLiteral("0.1.2.3.4.5.6.7alpha ") << 15 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7.8alpha ") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8alpha ") << 17 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7.8.alpha") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8.alpha") << 17 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7.8 alpha") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8 alpha") << 17 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7.8 alp ha") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8 alp ha") << 17 << false;
+ QTest::newRow("0.1.2.3.4.5.6.7.8alp ha") << QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 } << QVersionNumber(QList<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 }) << QStringLiteral("0.1.2.3.4.5.6.7.8") << QStringLiteral("0.1.2.3.4.5.6.7.8alp ha") << 17 << false;
+ QTest::newRow("10.09") << QList<int> { 10, 9 } << QVersionNumber(QList<int> { 10, 9 }) << QStringLiteral("10.9") << QStringLiteral("10.09") << 5 << false;
+ QTest::newRow("10.0x") << QList<int> { 10, 0 } << QVersionNumber(QList<int> { 10, 0 }) << QStringLiteral("10.0") << QStringLiteral("10.0x") << 4 << false;
+ QTest::newRow("10.0xTest") << QList<int> { 10, 0 } << QVersionNumber(QList<int> { 10, 0 }) << QStringLiteral("10.0") << QStringLiteral("10.0xTest") << 4 << false;
+ QTest::newRow("127.09") << QList<int> { 127, 9 } << QVersionNumber(QList<int> { 127, 9 }) << QStringLiteral("127.9") << QStringLiteral("127.09") << 6 << false;
+ QTest::newRow("127.0x") << QList<int> { 127, 0 } << QVersionNumber(QList<int> { 127, 0 }) << QStringLiteral("127.0") << QStringLiteral("127.0x") << 5 << false;
+ QTest::newRow("127.0xTest") << QList<int> { 127, 0 } << QVersionNumber(QList<int> { 127, 0 }) << QStringLiteral("127.0") << QStringLiteral("127.0xTest") << 5 << false;
+ QTest::newRow("128.09") << QList<int> { 128, 9 } << QVersionNumber(QList<int> { 128, 9 }) << QStringLiteral("128.9") << QStringLiteral("128.09") << 6 << false;
+ QTest::newRow("128.0x") << QList<int> { 128, 0 } << QVersionNumber(QList<int> { 128, 0 }) << QStringLiteral("128.0") << QStringLiteral("128.0x") << 5 << false;
+ QTest::newRow("128.0xTest") << QList<int> { 128, 0 } << QVersionNumber(QList<int> { 128, 0 }) << QStringLiteral("128.0") << QStringLiteral("128.0xTest") << 5 << false;
}
namespace UglyOperator {
// ugh, but the alternative (operator <<) is even worse...
-static inline QVector<int> operator+(QVector<int> v, int i) { v.push_back(i); return v; }
+static inline QList<int> operator+(QList<int> v, int i) { v.push_back(i); return v; }
}
void tst_QVersionNumber::comparisonData()
@@ -196,7 +176,7 @@ void tst_QVersionNumber::comparisonData()
QTest::newRow("0.-129, 0") << QVersionNumber(0, -129) << QVersionNumber(0) << false << true << true << true << false << false << -129 << false << QVersionNumber(0);
QTest::newRow("0, 0.-129") << QVersionNumber(0) << QVersionNumber(0, -129) << false << true << false << false << true << true << 129 << true << QVersionNumber(0);
- const QVector<int> common = QVector<int>() << 0 << 1 << 2 << 3 << 4 << 5 << 6;
+ const QList<int> common = QList<int>({ 0, 1, 2, 3, 4, 5, 6 });
using namespace UglyOperator;
QTest::newRow("0.1.2.3.4.5.6.0.1.2, 0.1.2.3.4.5.6.0.1") << QVersionNumber(common + 0 + 1 + 2) << QVersionNumber(common + 0 + 1) << false << true << false << false << true << true << 2 << false << QVersionNumber(common + 0 + 1);
QTest::newRow("0.1.2.3.4.5.6.0.1, 0.1.2.3.4.5.6.0.1.2") << QVersionNumber(common + 0 + 1) << QVersionNumber(common + 0 + 1 + 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(common + 0 + 1);
@@ -213,7 +193,7 @@ void tst_QVersionNumber::comparisonData()
void tst_QVersionNumber::initTestCase()
{
- qRegisterMetaType<QVector<int> >();
+ qRegisterMetaType<QList<int>>();
}
void tst_QVersionNumber::constructorDefault()
@@ -223,7 +203,7 @@ void tst_QVersionNumber::constructorDefault()
QCOMPARE(version.majorVersion(), 0);
QCOMPARE(version.minorVersion(), 0);
QCOMPARE(version.microVersion(), 0);
- QCOMPARE(version.segments(), QVector<int>());
+ QVERIFY(version.segments().isEmpty());
}
void tst_QVersionNumber::constructorVersioned_data()
@@ -233,7 +213,7 @@ void tst_QVersionNumber::constructorVersioned_data()
void tst_QVersionNumber::constructorVersioned()
{
- QFETCH(QVector<int>, segments);
+ QFETCH(QList<int>, segments);
QFETCH(QVersionNumber, expectedVersion);
QVersionNumber version(segments);
@@ -246,17 +226,17 @@ void tst_QVersionNumber::constructorVersioned()
void tst_QVersionNumber::constructorExplicit()
{
QVersionNumber v1(1);
- QVersionNumber v2(QVector<int>() << 1);
+ QVersionNumber v2(QList<int>({ 1 }));
QCOMPARE(v1.segments(), v2.segments());
QVersionNumber v3(1, 2);
- QVersionNumber v4(QVector<int>() << 1 << 2);
+ QVersionNumber v4(QList<int>({ 1, 2 }));
QCOMPARE(v3.segments(), v4.segments());
QVersionNumber v5(1, 2, 3);
- QVersionNumber v6(QVector<int>() << 1 << 2 << 3);
+ QVersionNumber v6(QList<int>({ 1, 2, 3 }));
QCOMPARE(v5.segments(), v6.segments());
@@ -264,6 +244,11 @@ void tst_QVersionNumber::constructorExplicit()
QVersionNumber v8 = {4, 5, 6};
QCOMPARE(v7.segments(), v8.segments());
+
+ QVersionNumber v9(4, 5, 6);
+ QVersionNumber vA({4, 5, 6});
+
+ QCOMPARE(v9.segments(), vA.segments());
}
void tst_QVersionNumber::constructorCopy_data()
@@ -273,7 +258,7 @@ void tst_QVersionNumber::constructorCopy_data()
void tst_QVersionNumber::constructorCopy()
{
- QFETCH(QVector<int>, segments);
+ QFETCH(QList<int>, segments);
QFETCH(QVersionNumber, expectedVersion);
QVersionNumber original(segments);
@@ -418,14 +403,14 @@ void tst_QVersionNumber::normalized_data()
QTest::addColumn<QVersionNumber>("version");
QTest::addColumn<QVersionNumber>("expected");
- QTest::newRow("0") << QVersionNumber(0) << QVersionNumber();
- QTest::newRow("1") << QVersionNumber(1) << QVersionNumber(1);
- QTest::newRow("1.2") << QVersionNumber(1, 2) << QVersionNumber(1, 2);
- QTest::newRow("1.0") << QVersionNumber(1, 0) << QVersionNumber(1);
- QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << QVersionNumber(1);
- QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << QVersionNumber(1, 0, 1);
- QTest::newRow("1.0.1.0") << QVersionNumber(QVector<int>() << 1 << 0 << 1 << 0) << QVersionNumber(1, 0, 1);
- QTest::newRow("0.0.1.0") << QVersionNumber(QVector<int>() << 0 << 0 << 1 << 0) << QVersionNumber(0, 0, 1);
+ QTest::newRow("0") << QVersionNumber(0) << QVersionNumber();
+ QTest::newRow("1") << QVersionNumber(1) << QVersionNumber(1);
+ QTest::newRow("1.2") << QVersionNumber(1, 2) << QVersionNumber(1, 2);
+ QTest::newRow("1.0") << QVersionNumber(1, 0) << QVersionNumber(1);
+ QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << QVersionNumber(1);
+ QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << QVersionNumber(1, 0, 1);
+ QTest::newRow("1.0.1.0") << QVersionNumber(QList<int>({ 1, 0, 1, 0 })) << QVersionNumber(1, 0, 1);
+ QTest::newRow("0.0.1.0") << QVersionNumber(QList<int>({ 0, 0, 1, 0 })) << QVersionNumber(0, 0, 1);
}
void tst_QVersionNumber::normalized()
@@ -442,13 +427,13 @@ void tst_QVersionNumber::isNormalized_data()
QTest::addColumn<QVersionNumber>("version");
QTest::addColumn<bool>("expected");
- QTest::newRow("null") << QVersionNumber() << true;
- QTest::newRow("0") << QVersionNumber(0) << false;
- QTest::newRow("1") << QVersionNumber(1) << true;
- QTest::newRow("1.2") << QVersionNumber(1, 2) << true;
- QTest::newRow("1.0") << QVersionNumber(1, 0) << false;
- QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << false;
- QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << true;
+ QTest::newRow("null") << QVersionNumber() << true;
+ QTest::newRow("0") << QVersionNumber(0) << false;
+ QTest::newRow("1") << QVersionNumber(1) << true;
+ QTest::newRow("1.2") << QVersionNumber(1, 2) << true;
+ QTest::newRow("1.0") << QVersionNumber(1, 0) << false;
+ QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << false;
+ QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << true;
}
void tst_QVersionNumber::isNormalized()
@@ -466,7 +451,7 @@ void tst_QVersionNumber::assignment_data()
void tst_QVersionNumber::assignment()
{
- QFETCH(QVector<int>, segments);
+ QFETCH(QList<int>, segments);
QFETCH(QVersionNumber, expectedVersion);
QVersionNumber original(segments);
@@ -488,17 +473,17 @@ void tst_QVersionNumber::fromString_data()
const QString largerThanIntCanHoldString1 = "0." + QString::number(largerThanIntCanHold);
QTest::newRow(qPrintable(largerThanIntCanHoldString0))
- << QVector<int>() << QVersionNumber() << QString() << largerThanIntCanHoldString0 << 0 << true;
+ << QList<int>() << QVersionNumber() << QString() << largerThanIntCanHoldString0 << 0 << true;
QTest::newRow(qPrintable(largerThanIntCanHoldString1))
- << QVector<int>(0) << QVersionNumber(0) << QStringLiteral("0") << largerThanIntCanHoldString1 << 1 << true;
+ << QList<int>(0) << QVersionNumber(0) << QStringLiteral("0") << largerThanIntCanHoldString1 << 1 << true;
const QString largerThanULongLongCanHoldString0 = QString::number(std::numeric_limits<qulonglong>::max()) + "0.0"; // 10x ULLONG_MAX
const QString largerThanULongLongCanHoldString1 = "0." + QString::number(std::numeric_limits<qulonglong>::max()) + '0'; // 10x ULLONG_MAX
QTest::newRow(qPrintable(largerThanULongLongCanHoldString0))
- << QVector<int>() << QVersionNumber() << QString() << largerThanULongLongCanHoldString0 << 0 << true;
+ << QList<int>() << QVersionNumber() << QString() << largerThanULongLongCanHoldString0 << 0 << true;
QTest::newRow(qPrintable(largerThanULongLongCanHoldString1))
- << QVector<int>(0) << QVersionNumber(0) << QStringLiteral("0") << largerThanULongLongCanHoldString1 << 1 << true;
+ << QList<int>(0) << QVersionNumber(0) << QStringLiteral("0") << largerThanULongLongCanHoldString1 << 1 << true;
}
void tst_QVersionNumber::fromString()
@@ -507,7 +492,7 @@ void tst_QVersionNumber::fromString()
QFETCH(QVersionNumber, expectedVersion);
QFETCH(int, suffixIndex);
- int index;
+ qsizetype index;
QCOMPARE(QVersionNumber::fromString(constructionString), expectedVersion);
QCOMPARE(QVersionNumber::fromString(constructionString, &index), expectedVersion);
QCOMPARE(index, suffixIndex);
@@ -519,16 +504,56 @@ void tst_QVersionNumber::fromString()
QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1())), expectedVersion);
QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &index), expectedVersion);
QCOMPARE(index, suffixIndex);
+
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ // check deprecated `int *suffixIndex` overload, too
+ {
+ int i;
+ QCOMPARE(QVersionNumber::fromString(constructionString, &i), expectedVersion);
+ QCOMPARE(i, suffixIndex);
+
+ QCOMPARE(QVersionNumber::fromString(QStringView(constructionString), &i), expectedVersion);
+ QCOMPARE(i, suffixIndex);
+
+ QCOMPARE(QVersionNumber::fromString(QLatin1String(constructionString.toLatin1()), &i), expectedVersion);
+ QCOMPARE(i, suffixIndex);
+ }
+ QT_WARNING_POP
+#endif
+}
+
+void tst_QVersionNumber::fromString_extra()
+{
+ // check the overloaded fromString() functions aren't ambiguous
+ // when passing explicit nullptr:
+ {
+ auto v = QVersionNumber::fromString("1.2.3-rc1", nullptr);
+ QCOMPARE(v, QVersionNumber({1, 2, 3}));
+ }
+ {
+ auto v = QVersionNumber::fromString("1.2.3-rc1", 0);
+ QCOMPARE(v, QVersionNumber({1, 2, 3}));
+ }
+
+ // check the UTF16->L1 conversion isn't doing something weird
+ {
+ qsizetype i = -1;
+ auto v = QVersionNumber::fromString(u"1.0ı", &i); // LATIN SMALL LETTER DOTLESS I
+ QCOMPARE(v, QVersionNumber(1, 0));
+ QCOMPARE(i, 3);
+ }
}
void tst_QVersionNumber::toString_data()
{
singleInstanceData();
- // segments expectedVersion expectedString constructionString suffixIndex null
- QTest::newRow("-1") << (QVector<int>() << -1) << QVersionNumber(-1) << QString("-1") << QString() << 0 << true;
- QTest::newRow("-1.0") << (QVector<int>() << -1 << 0) << QVersionNumber(-1, 0) << QString("-1.0") << QString() << 0 << true;
- QTest::newRow("1.-2") << (QVector<int>() << 1 << -2) << QVersionNumber(1, -2) << QString("1.-2") << QString() << 0 << true;
+ // segments expectedVersion expectedString constructionString suffixIndex null
+ QTest::newRow("-1") << (QList<int>({ -1 })) << QVersionNumber(-1) << QString("-1") << QString() << 0 << true;
+ QTest::newRow("-1.0") << (QList<int>({ -1, 0 })) << QVersionNumber(-1, 0) << QString("-1.0") << QString() << 0 << true;
+ QTest::newRow("1.-2") << (QList<int>({ 1, -2 })) << QVersionNumber(1, -2) << QString("1.-2") << QString() << 0 << true;
}
void tst_QVersionNumber::toString()
@@ -546,7 +571,7 @@ void tst_QVersionNumber::isNull_data()
void tst_QVersionNumber::isNull()
{
- QFETCH(QVector<int>, segments);
+ QFETCH(QList<int>, segments);
QFETCH(bool, isNull);
QVersionNumber version(segments);
@@ -554,6 +579,45 @@ void tst_QVersionNumber::isNull()
QCOMPARE(version.isNull(), isNull);
}
+void tst_QVersionNumber::iterators_data()
+{
+ singleInstanceData();
+}
+
+void tst_QVersionNumber::iterators()
+{
+ QFETCH(const QList<int>, segments);
+ QFETCH(QVersionNumber, expectedVersion);
+
+ QVERIFY(std::equal(expectedVersion.begin(), expectedVersion.end(),
+ segments.begin(), segments.end()));
+ QVERIFY(std::equal(std::as_const(expectedVersion).begin(), std::as_const(expectedVersion).end(),
+ segments.begin(), segments.end()));
+ QVERIFY(std::equal(expectedVersion.cbegin(), expectedVersion.cend(),
+ segments.cbegin(), segments.cend()));
+ QVERIFY(std::equal(expectedVersion.rbegin(), expectedVersion.rend(),
+ segments.rbegin(), segments.rend()));
+ QVERIFY(std::equal(std::as_const(expectedVersion).rbegin(), std::as_const(expectedVersion).rend(),
+ segments.rbegin(), segments.rend()));
+ QVERIFY(std::equal(expectedVersion.crbegin(), expectedVersion.crend(),
+ segments.crbegin(), segments.crend()));
+}
+
+void tst_QVersionNumber::iteratorsAreDefaultConstructible()
+{
+ static_assert(std::is_default_constructible_v<QVersionNumber::const_iterator>);
+ [[maybe_unused]] QVersionNumber::const_iterator ci;
+ [[maybe_unused]] QVersionNumber::const_reverse_iterator cri;
+}
+
+void tst_QVersionNumber::valueInitializedIteratorsCompareEqual()
+{
+ QVersionNumber::const_iterator it = {}, jt = {};
+ QCOMPARE_EQ(it, jt);
+ QVersionNumber::const_reverse_iterator rit = {}, rjt = {};
+ QCOMPARE_EQ(rit, rjt);
+}
+
void tst_QVersionNumber::serialize_data()
{
singleInstanceData();
@@ -561,7 +625,7 @@ void tst_QVersionNumber::serialize_data()
void tst_QVersionNumber::serialize()
{
- QFETCH(QVector<int>, segments);
+ QFETCH(QList<int>, segments);
QVersionNumber original(segments);
QVersionNumber version;
@@ -597,9 +661,9 @@ void tst_QVersionNumber::moveSemantics()
v2 = std::move(v1);
QCOMPARE(v2, QVersionNumber(1, 2, 3));
}
- // QVersionNumber(QVector<int> &&)
+ // QVersionNumber(QList<int> &&)
{
- QVector<int> segments = QVector<int>() << 1 << 2 << 3;
+ QList<int> segments = QList<int>({ 1, 2, 3});
QVersionNumber v1(segments);
QVersionNumber v2(std::move(segments));
QVERIFY(!v1.isNull());
@@ -624,7 +688,7 @@ void tst_QVersionNumber::moveSemantics()
{
QVersionNumber v(1, 2, 3);
QVERIFY(!v.isNull());
- QVector<int> segments;
+ QList<int> segments;
segments = v.segments();
QVERIFY(!v.isNull());
QVERIFY(!segments.empty());
diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro
deleted file mode 100644
index 5a7c8478f1..0000000000
--- a/tests/auto/corelib/tools/tools.pro
+++ /dev/null
@@ -1,43 +0,0 @@
-TEMPLATE=subdirs
-SUBDIRS=\
- collections \
- containerapisymmetry \
- qalgorithms \
- qarraydata \
- qbitarray \
- qcache \
- qcommandlineparser \
- qcontiguouscache \
- qcryptographichash \
- qeasingcurve \
- qexplicitlyshareddatapointer \
- qfreelist \
- qhash \
- qhashfunctions \
- qline \
- qlinkedlist \
- qmakearray \
- qmap \
- qmargins \
- qmessageauthenticationcode \
- qoffsetstringarray \
- qpair \
- qpoint \
- qpointf \
- qqueue \
- qrect \
- qringbuffer \
- qscopedpointer \
- qscopedvaluerollback \
- qscopeguard \
- qset \
- qsharedpointer \
- qsize \
- qsizef \
- qstl \
- qtimeline \
- qvarlengtharray \
- qvector \
- qversionnumber
-
-darwin: SUBDIRS += qmacautoreleasepool