summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/collections/tst_collections.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/tools/collections/tst_collections.cpp')
-rw-r--r--tests/auto/corelib/tools/collections/tst_collections.cpp184
1 files changed, 117 insertions, 67 deletions
diff --git a/tests/auto/corelib/tools/collections/tst_collections.cpp b/tests/auto/corelib/tools/collections/tst_collections.cpp
index 6d21de9ae7..2fab6cae3a 100644
--- a/tests/auto/corelib/tools/collections/tst_collections.cpp
+++ b/tests/auto/corelib/tools/collections/tst_collections.cpp
@@ -1,31 +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
+#undef QT_NO_FOREACH // this file tests Q_FOREACH over containers (centralize in a tst_qforeach?)
// test the container forwards
#include <QtContainerFwd>
@@ -63,6 +39,9 @@ void foo()
#include <QTest>
#include <QVector>
+#include <QScopedPointer>
+#include <QThread>
+#include <QSemaphore>
#include <algorithm>
@@ -123,6 +102,15 @@ 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 {
@@ -300,10 +288,15 @@ 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);
}
@@ -537,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"));
@@ -692,7 +685,7 @@ QT_WARNING_POP
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"));
}
@@ -2026,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()));
@@ -2079,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();
@@ -2701,7 +2694,7 @@ void tst_Collections::vector_stl()
QFETCH(QStringList, elements);
QList<QString> vector;
- for (int i = 0; i < elements.count(); ++i)
+ for (int i = 0; i < elements.size(); ++i)
vector << elements.at(i);
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
@@ -2736,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)
@@ -2829,7 +2822,7 @@ void instantiateContainer()
container.clear();
container.contains(value);
- container.count();
+ container.size();
container.empty();
container.isEmpty();
container.size();
@@ -3077,9 +3070,8 @@ class T2;
void tst_Collections::forwardDeclared()
{
-#define COMMA ,
-#define TEST(type) do { \
- using C = type; \
+#define TEST(...) do { \
+ using C = __VA_ARGS__; \
C *x = nullptr; \
C::iterator i; \
C::const_iterator j; \
@@ -3088,16 +3080,15 @@ void tst_Collections::forwardDeclared()
Q_UNUSED(j); \
} while (false)
- TEST(QHash<Key1 COMMA T1>);
- TEST(QMap<Key1 COMMA T1>);
- TEST(QMultiMap<Key1 COMMA T1>);
+ 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
-#undef COMMA
{
using C = QPair<T1, T2>;
@@ -3254,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>();
}
@@ -3279,7 +3270,7 @@ 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>();
}
@@ -3346,7 +3337,7 @@ void tst_Collections::QTBUG13079_collectionInsideCollection()
QSet<QTBUG13079_Node<QSet> > nodeSet;
nodeSet << QTBUG13079_Node<QSet>();
nodeSet = nodeSet.begin()->children;
- QCOMPARE(nodeSet.count(), 0);
+ QCOMPARE(nodeSet.size(), 0);
}
QTBUG13079_collectionInsideCollectionAssocImpl<QMap>();
@@ -3368,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;
@@ -3405,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;
@@ -3417,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
@@ -3440,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])));
}
@@ -3461,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])));
}
@@ -3474,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])));
}
@@ -3500,8 +3494,8 @@ 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])));
}
@@ -3511,8 +3505,8 @@ template<class Container> void insert_remove_loop_impl()
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.count()), sizeof(expect6)/sizeof(int));
- for (int i = 0; i < t.count(); i++) {
+ QCOMPARE(size_t(t.size()), sizeof(expect6)/sizeof(int));
+ for (int i = 0; i < t.size(); i++) {
QCOMPARE(t[i], T(IntOrString(expect6[i])));
}
@@ -3545,7 +3539,63 @@ void tst_Collections::insert_remove_loop()
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"