QHash, QMultiHash: extend tests
Extend tests to explicitly check the behavior of empty default-constructed containers. Also add some missing tests for the existing methods (mostly for QMultiHash) and correct some end()s to cend()s in comparisons. Task-number: QTBUG-91736 Change-Id: Ic9e1b86ef67f6bca2751a65a8589b2f7e0ebb5ea Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> (cherry picked from commit af000203359d7a0df2dc4901db605c4e18511e99) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
0968580d62
commit
5b27736c87
@ -61,12 +61,18 @@ private slots:
|
||||
void qmultihash_specific();
|
||||
void qmultihash_qhash_rvalue_ref_ctor();
|
||||
void qmultihash_qhash_rvalue_ref_unite();
|
||||
void qmultihashUnite();
|
||||
|
||||
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 const_shared_null();
|
||||
@ -84,6 +90,9 @@ private slots:
|
||||
void stdHash();
|
||||
|
||||
void countInEmptyHash();
|
||||
void removeInEmptyHash();
|
||||
void valueInEmptyHash();
|
||||
void fineTuningInEmptyHash();
|
||||
};
|
||||
|
||||
struct IdentityTracker {
|
||||
@ -488,6 +497,7 @@ QT_WARNING_POP
|
||||
{
|
||||
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);
|
||||
@ -560,6 +570,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"));
|
||||
@ -590,6 +601,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);
|
||||
@ -706,6 +718,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()
|
||||
@ -713,13 +744,15 @@ 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
|
||||
@ -780,6 +813,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");
|
||||
@ -788,6 +822,10 @@ void tst_QHash::constFind()
|
||||
QCOMPARE(map1.constFind(1).value(), QLatin1String("Mayer"));
|
||||
QCOMPARE(map1.constFind(2).value(), QLatin1String("Hej"));
|
||||
|
||||
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);
|
||||
@ -811,6 +849,9 @@ 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));
|
||||
|
||||
@ -889,13 +930,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));
|
||||
QCOMPARE(map.take(3), QLatin1String("drei"));
|
||||
QVERIFY(!map.contains(3));
|
||||
}
|
||||
{
|
||||
QMultiHash<int, QString> hash;
|
||||
QCOMPARE(hash.take(1), QString());
|
||||
QVERIFY(!hash.isDetached());
|
||||
|
||||
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
|
||||
@ -1194,14 +1255,144 @@ void tst_QHash::iterators()
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
@ -1216,20 +1407,54 @@ void tst_QHash::keyIterator()
|
||||
QCOMPARE(*key_it, it.key());
|
||||
QCOMPARE(*(key_it++), (it++).key());
|
||||
if (key_it != hash.keyEnd()) {
|
||||
QVERIFY(it != hash.end());
|
||||
QVERIFY(it != hash.cend());
|
||||
++key_it;
|
||||
++it;
|
||||
if (key_it != hash.keyEnd())
|
||||
QCOMPARE(*key_it, it.key());
|
||||
else
|
||||
QVERIFY(it == hash.end());
|
||||
QVERIFY(it == hash.cend());
|
||||
}
|
||||
|
||||
QCOMPARE(std::count(hash.keyBegin(), hash.keyEnd(), 99), 1);
|
||||
|
||||
// DefaultConstructible test
|
||||
typedef QHash<int, int>::key_iterator keyIterator;
|
||||
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()
|
||||
@ -1274,7 +1499,7 @@ void tst_QHash::keyValueIterator()
|
||||
|
||||
++it;
|
||||
++key_value_it;
|
||||
if (it != hash.end())
|
||||
if (it != hash.cend())
|
||||
QCOMPARE(*key_value_it, entry_type(it.key(), it.value()));
|
||||
else
|
||||
QVERIFY(key_value_it == hash.constKeyValueEnd());
|
||||
@ -1284,6 +1509,88 @@ void tst_QHash::keyValueIterator()
|
||||
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
|
||||
@ -1322,16 +1629,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));
|
||||
@ -1403,6 +1718,12 @@ void tst_QHash::qmultihash_specific()
|
||||
QVERIFY(i.value() == 98);
|
||||
}
|
||||
|
||||
QCOMPARE(hash1.count(9), 8);
|
||||
QCOMPARE(hash1.count(), 44);
|
||||
hash1.remove(9);
|
||||
QCOMPARE(hash1.count(9), 0);
|
||||
QCOMPARE(hash1.count(), 36);
|
||||
|
||||
{
|
||||
QMultiHash<int, int> map1;
|
||||
map1.insert(42, 1);
|
||||
@ -1541,12 +1862,150 @@ void tst_QHash::qmultihash_qhash_rvalue_ref_unite()
|
||||
}
|
||||
}
|
||||
|
||||
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::keys_values_uniqueKeys()
|
||||
{
|
||||
QMultiHash<QString, int> hash;
|
||||
QVERIFY(hash.uniqueKeys().isEmpty());
|
||||
QVERIFY(hash.keys().isEmpty());
|
||||
QVERIFY(hash.values().isEmpty());
|
||||
QVERIFY(!hash.isDetached());
|
||||
|
||||
hash.insert("alpha", 1);
|
||||
QVERIFY(sorted(hash.keys()) == (QList<QString>() << "alpha"));
|
||||
@ -2067,14 +2526,75 @@ void tst_QHash::countInEmptyHash()
|
||||
{
|
||||
{
|
||||
QHash<int, int> hash;
|
||||
QCOMPARE(hash.count(), 0);
|
||||
QCOMPARE(hash.count(42), 0);
|
||||
}
|
||||
|
||||
{
|
||||
QMultiHash<int, int> hash;
|
||||
QCOMPARE(hash.count(), 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);
|
||||
QVERIFY(qFuzzyIsNull(hash.load_factor()));
|
||||
QVERIFY(!hash.isDetached());
|
||||
|
||||
hash.reserve(10);
|
||||
QVERIFY(hash.capacity() >= 10);
|
||||
hash.squeeze();
|
||||
QVERIFY(hash.capacity() > 0);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QHash)
|
||||
#include "tst_qhash.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user