From 0968580d62c74992441670e8501e5e608f260fe9 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Mon, 12 Jul 2021 18:15:03 +0200 Subject: QList: extend tests This patch mostly introduces some test improvements to check the calls of different methods on an empty default-constructed container. Apart from that some other tests are added to extend test coverage. Task-number: QTBUG-91736 Change-Id: If2bc96158462292bbdf8504942141af94568c729 Reviewed-by: Edward Welbourne Reviewed-by: Andrei Golubev (cherry picked from commit 3ee587f8fa4086b0cc9ba85f08c26ee646344177) --- tests/auto/corelib/tools/qlist/tst_qlist.cpp | 440 ++++++++++++++++++++++++++- 1 file changed, 426 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index 75da6bcd41..d9b5512bbb 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -284,6 +284,7 @@ private slots: void prependInt() const; void prependMovable() const; void prependCustom() const; + void prependRvalue() const; void qhashInt() const { qhash(); } void qhashMovable() const { qhash(); } void qhashCustom() const { qhash(); } @@ -302,6 +303,8 @@ private slots: void resizeToZero() const; void resizeToTheSameSize_data(); void resizeToTheSameSize() const; + void iterators() const; + void constIterators() const; void reverseIterators() const; void sizeInt() const; void sizeMovable() const; @@ -346,11 +349,15 @@ private slots: void emplaceConsistentWithStdVectorMovable(); void emplaceConsistentWithStdVectorQString(); void emplaceReturnsIterator(); + void emplaceFront() const; + void emplaceFrontReturnsRef() const; void emplaceBack(); void emplaceBackReturnsRef(); void emplaceWithElementFromTheSameContainer(); void emplaceWithElementFromTheSameContainer_data(); - + void replaceInt() const { replace(); } + void replaceCustom() const { replace(); } + void replaceMovable() const { replace(); } void fromReadOnlyData() const; void qtbug_90359() const; void reinsertToBeginInt_qtbug91360() const { reinsertToBegin(); } @@ -410,6 +417,7 @@ private: template void detachThreadSafety() const; template void emplaceImpl() const; template void emplaceConsistentWithStdVectorImpl() const; + template void replace() const; template void reinsert(Reinsert op) const; template @@ -768,6 +776,37 @@ void tst_QList::append() const QCOMPARE(v, combined); } + { + const QList otherVec { SimpleValue::at(0), + SimpleValue::at(1), + SimpleValue::at(2), + SimpleValue::at(3) }; + QList myvec; + myvec.append(otherVec.cbegin(), otherVec.cbegin() + 3); + QCOMPARE(myvec.size(), 3); + QCOMPARE(myvec, QList() << SimpleValue::at(0) + << SimpleValue::at(1) + << SimpleValue::at(2)); + } + { + QList emptyVec; + QList otherEmptyVec; + + emptyVec.append(otherEmptyVec); + + QVERIFY(emptyVec.isEmpty()); + QVERIFY(!emptyVec.isDetached()); + QVERIFY(!otherEmptyVec.isDetached()); + } + { + QList myvec { SimpleValue::at(0), SimpleValue::at(1) }; + QList emptyVec; + + myvec.append(emptyVec); + QVERIFY(emptyVec.isEmpty()); + QVERIFY(!emptyVec.isDetached()); + QCOMPARE(myvec, QList({ SimpleValue::at(0), SimpleValue::at(1) })); + } } void tst_QList::appendInt() const @@ -795,9 +834,15 @@ void tst_QList::appendRvalue() const v.append("hello"); QString world = "world"; v.append(std::move(world)); - QVERIFY(world.isEmpty()); QCOMPARE(v.front(), QString("hello")); QCOMPARE(v.back(), QString("world")); + + // check append rvalue to empty list + QList myvec; + QString test = "test"; + myvec.append(std::move(test)); + QCOMPARE(myvec.size(), 1); + QCOMPARE(myvec.front(), QString("test")); } struct ConstructionCounted @@ -1028,6 +1073,7 @@ void tst_QList::capacity() const // 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::at(0) << SimpleValue::at(1) << SimpleValue::at(2); @@ -1073,6 +1119,9 @@ template void tst_QList::clear() const { QList myvec; + myvec.clear(); + QVERIFY(!myvec.isDetached()); + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); const auto oldCapacity = myvec.capacity(); @@ -1105,14 +1154,21 @@ void tst_QList::constData() const { int arr[] = { 42, 43, 44 }; QList myvec; + QCOMPARE(myvec.constData(), nullptr); + QVERIFY(!myvec.isDetached()); + myvec << 42 << 43 << 44; - QVERIFY(memcmp(myvec.constData(), reinterpret_cast(&arr), sizeof(int) * 3) == 0); + QCOMPARE(memcmp(myvec.constData(), reinterpret_cast(&arr), sizeof(int) * 3), 0); } void tst_QList::contains() const { QList myvec; + + QVERIFY(!myvec.contains(QLatin1String("test"))); + QVERIFY(!myvec.isDetached()); + myvec << "aaa" << "bbb" << "ccc"; QVERIFY(myvec.contains(QLatin1String("aaa"))); @@ -1133,6 +1189,7 @@ void tst_QList::count() const // zero size QList myvec; QVERIFY(myvec.count() == 0); + QVERIFY(!myvec.isDetached()); // grow myvec.append(SimpleValue::at(0)); @@ -1150,6 +1207,9 @@ void tst_QList::count() const // count of items { QList myvec; + QCOMPARE(myvec.count(SimpleValue::at(0)), 0); + QVERIFY(!myvec.isDetached()); + myvec << SimpleValue::at(0) << SimpleValue::at(1) << SimpleValue::at(2); // initial tests @@ -1215,6 +1275,8 @@ void tst_QList::cpp17ctad() const void tst_QList::data() const { QList myvec; + QCOMPARE(myvec.data(), nullptr); + myvec << 42 << 43 << 44; // make sure it starts off ok @@ -1227,7 +1289,11 @@ void tst_QList::data() const QCOMPARE(*(myvec.data() + 1), 69); int arr[] = { 42, 69, 44 }; - QVERIFY(memcmp(myvec.data(), reinterpret_cast(&arr), sizeof(int) * 3) == 0); + QCOMPARE(memcmp(myvec.data(), reinterpret_cast(&arr), sizeof(int) * 3), 0); + + const QList constVec = myvec; + QCOMPARE(memcmp(constVec.data(), reinterpret_cast(&arr), sizeof(int) * 3), 0); + QVERIFY(!constVec.isDetached()); // const data() does not detach() } template @@ -1237,6 +1303,7 @@ void tst_QList::empty() const // starts empty QVERIFY(myvec.empty()); + QVERIFY(!myvec.isDetached()); // not empty myvec.append(SimpleValue::at(2)); @@ -1524,6 +1591,10 @@ void tst_QList::fill() const { QList myvec; + // fill an empty list - it should resize + myvec.fill(SimpleValue::at(1), 2); + QCOMPARE(myvec, QList({ SimpleValue::at(1), SimpleValue::at(1) })); + // resize myvec.resize(5); myvec.fill(SimpleValue::at(1)); @@ -1768,6 +1839,11 @@ void tst_QList::fromStdVector() const void tst_QList::indexOf() const { QList 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); @@ -1855,6 +1931,52 @@ void tst_QList::insert() const QCOMPARE(myvec, QList() << tB << tB << tX << tZ << ti << ti << tA << tB << tC << tT); QCOMPARE(myvec2, myvec); + + // Different insert() into empty list overloads + { + QList myvec; + auto it = myvec.insert(0, tA); + QCOMPARE(myvec.size(), 1); + QCOMPARE(myvec.front(), tA); + QCOMPARE(it, myvec.begin()); + } + { + QList myvec; + auto it = myvec.insert(0, 3, tX); + QCOMPARE(myvec.size(), 3); + QCOMPARE(myvec, QList({ tX, tX, tX })); + QCOMPARE(it, myvec.begin()); + } + { + QList myvec; + auto it = myvec.insert(myvec.cbegin(), tA); + QCOMPARE(myvec.size(), 1); + QCOMPARE(myvec.front(), tA); + QCOMPARE(it, myvec.begin()); + } + { + QList myvec; + auto it = myvec.insert(myvec.cbegin(), 3, tX); + QCOMPARE(myvec.size(), 3); + QCOMPARE(myvec, QList({ tX, tX, tX })); + QCOMPARE(it, myvec.begin()); + } + { + QList 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 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::insertInt() const @@ -1898,6 +2020,7 @@ void tst_QList::isEmpty() const // starts ok QVERIFY(myvec.isEmpty()); + QVERIFY(!myvec.isDetached()); // not empty now myvec.append(QLatin1String("hello there")); @@ -2003,6 +2126,11 @@ void tst_QList::constLast() const void tst_QList::lastIndexOf() const { QList 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); @@ -2026,6 +2154,12 @@ void tst_QList::lastIndexOf() const void tst_QList::mid() const { QList list; + + QCOMPARE(list.mid(4, 2), QList()); + QCOMPARE(list.mid(0, 3), QList()); + QCOMPARE(list.mid(-2, 3), QList()); + QVERIFY(!list.isDetached()); + list << "foo" << "bar" << "baz" << "bak" << "buck" << "hello" << "kitty"; QCOMPARE(list.mid(3, 3), QList() << "bak" << "buck" << "hello"); @@ -2102,11 +2236,19 @@ template void tst_QList::prepend() const { QList myvec; + T val1 = SimpleValue::at(0); T val2 = SimpleValue::at(1); T val3 = SimpleValue::at(2); T val4 = SimpleValue::at(3); T val5 = SimpleValue::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 @@ -2153,6 +2295,21 @@ void tst_QList::prependCustom() const QCOMPARE(instancesCount, Custom::counter.loadAcquire()); } +void tst_QList::prependRvalue() const +{ + QList 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({ "hello", "world" })); +} + void tst_QList::removeAllWithAlias() const { QList strings; @@ -2168,31 +2325,48 @@ void tst_QList::remove() const T val2 = SimpleValue::at(2); T val3 = SimpleValue::at(3); T val4 = SimpleValue::at(4); - myvec << val1 << val2 << val3; - myvec << val1 << val2 << val3; - myvec << val1 << val2 << val3; - // remove middle + T val5 = SimpleValue::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() << val1 << val3 << val1 << val2 << val3 << val1 << val2 << val3); + QCOMPARE(myvec, QList({ val1, val3, val4, val1, val2, val3, val4, val1, val2, val3, val4 })); + myvec.removeAt(6); + QCOMPARE(myvec, QList({ val1, val3, val4, val1, val2, val3, val1, val2, val3, val4 })); // removeOne() - QVERIFY(!myvec.removeOne(val4)); + QVERIFY(!myvec.removeOne(val5)); QVERIFY(myvec.removeOne(val2)); - QCOMPARE(myvec, QList() << val1 << val3 << val1 << val3 << val1 << val2 << val3); + QCOMPARE(myvec, QList({ val1, val3, val4, val1, val3, val1, val2, val3, val4 })); QList myvecCopy = myvec; QVERIFY(myvecCopy.isSharedWith(myvec)); // removeAll() - QCOMPARE(myvec.removeAll(val4), 0); + QCOMPARE(myvec.removeAll(val5), 0); QVERIFY(myvecCopy.isSharedWith(myvec)); QCOMPARE(myvec.removeAll(val1), 3); QVERIFY(!myvecCopy.isSharedWith(myvec)); - QCOMPARE(myvec, QList() << val3 << val3 << val2 << val3); + QCOMPARE(myvec, QList({ val3, val4, val3, val2, val3, val4 })); + QCOMPARE(myvecCopy, QList({ 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() << val3 << val3 << val3); + QCOMPARE(myvec, QList({ val3, val4, val3, val3, val4 })); + QCOMPARE(myvecCopy, QList({ val3, val4, val3, val2, val3, val4 })); + + // removeIf + count = myvec.removeIf([&val4](const T &val) { return val == val4; }); + QCOMPARE(count, 2); + QCOMPARE(myvec, QList({ val3, val3, val3 })); // remove rest myvec.remove(0, 3); @@ -2337,7 +2511,9 @@ void tst_QList::resizePOD_data() const 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; @@ -2353,6 +2529,9 @@ void tst_QList::resizePOD() const 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 @@ -2385,7 +2564,9 @@ void tst_QList::resizeComplexMovable_data() const 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; @@ -2403,6 +2584,8 @@ void tst_QList::resizeComplexMovable() const 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 @@ -2437,7 +2620,9 @@ void tst_QList::resizeComplex_data() const 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; @@ -2454,6 +2639,8 @@ void tst_QList::resizeComplex() const 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 @@ -2526,6 +2713,156 @@ void tst_QList::resizeToTheSameSize() const QCOMPARE(y.size(), x.size()); } +void tst_QList::iterators() const +{ + QList 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); + + std::advance(it, 7); + idx += 7; + QCOMPARE(*it, idx); + + it++; + idx++; + QCOMPARE(*it, idx); + + ++it; + ++idx; + QCOMPARE(*it, idx); + + std::advance(it, -3); + idx -= 3; + QCOMPARE(*it, idx); + + it--; + idx--; + QCOMPARE(*it, idx); + + --it; + --idx; + QCOMPARE(*it, idx); + + *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 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 v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + // stl-style iterators + qsizetype idx = 0; + auto it = v.cbegin(); + QCOMPARE(*it, idx); + + std::advance(it, 7); + idx += 7; + QCOMPARE(*it, idx); + + it++; + idx++; + QCOMPARE(*it, idx); + + ++it; + ++idx; + QCOMPARE(*it, idx); + + std::advance(it, -3); + idx -= 3; + QCOMPARE(*it, idx); + + it--; + idx--; + QCOMPARE(*it, idx); + + --it; + --idx; + QCOMPARE(*it, idx); + + // 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 v; @@ -2544,21 +2881,29 @@ void tst_QList::reverseIterators() const template void tst_QList::size() const { + // also verify that length() is an alias to size() + // zero size QList myvec; QVERIFY(myvec.size() == 0); + QCOMPARE(myvec.length(), myvec.size()); + QVERIFY(!myvec.isDetached()); // grow myvec.append(SimpleValue::at(0)); QVERIFY(myvec.size() == 1); + QCOMPARE(myvec.length(), myvec.size()); myvec.append(SimpleValue::at(1)); QVERIFY(myvec.size() == 2); + QCOMPARE(myvec.length(), myvec.size()); // shrink myvec.remove(0); QVERIFY(myvec.size() == 1); + QCOMPARE(myvec.length(), myvec.size()); myvec.remove(0); QVERIFY(myvec.size() == 0); + QCOMPARE(myvec.length(), myvec.size()); } void tst_QList::sizeInt() const @@ -2667,6 +3012,11 @@ void tst_QList::toStdVector() const void tst_QList::value() const { QList myvec; + + QCOMPARE(myvec.value(1), QString()); + QCOMPARE(myvec.value(-1, QLatin1String("default")), QLatin1String("default")); + QVERIFY(!myvec.isDetached()); + myvec << "A" << "B" << "C"; // valid calls @@ -2787,6 +3137,10 @@ void tst_QList::reserveZero() QList 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 @@ -3143,6 +3497,31 @@ void tst_QList::emplaceReturnsIterator() QCOMPARE(vec[0].i, 'p'); } +void tst_QList::emplaceFront() const +{ + QScopedValueRollback rollback(Movable::counter, 0); + + QList vec; + vec.emplaceFront('b'); + QCOMPARE(Movable::counter, 1); + + vec.emplaceFront('a'); + QCOMPARE(Movable::counter, 2); + + QCOMPARE(vec, QList({ 'a', 'b' })); +} + +void tst_QList::emplaceFrontReturnsRef() const +{ + QList vec; + + QCOMPARE(vec.emplaceFront('c').i, 'c'); + + vec.emplaceFront('b').i = 'a'; + + QCOMPARE(vec.front().i, 'a'); +} + void tst_QList::emplaceBack() { QScopedValueRollback rollback(Movable::counter, 0); @@ -3206,7 +3585,40 @@ void tst_QList::emplaceImpl() const 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 vec; + vec.emplace(vec.begin(), 'a'); + QCOMPARE(vec.size(), 1); + QCOMPARE(vec.front(), T('a')); + } + { + QList vec; + vec.emplace(0, 'a'); + QCOMPARE(vec.size(), 1); + QCOMPARE(vec.front(), T('a')); + } +} + +template +void tst_QList::replace() const +{ + QList 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 -- cgit v1.2.3