summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2024-02-02 11:10:30 -0800
committerThiago Macieira <thiago.macieira@intel.com>2024-02-12 17:01:33 -0800
commit1845d433277348542e496d3c38175ad0c5cbddde (patch)
tree0eace3b4d8a526e6eed5aac356da3845c92ab171 /tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
parentfee15182949e88682131399c50b679be83a75385 (diff)
tst_QHashFunctions: make the consistency check table-driven
So we can test more values. Because we are testing more values, we can't use QEXPECT_FAIL, because we can't guarantee a mismatch. Pick-to: 6.7 Task-number: QTBUG-116077 Task-number: QTBUG-116080 Change-Id: I664b9f014ffc48cbb49bfffd17b021719e6d612f Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Diffstat (limited to 'tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp')
-rw-r--r--tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp286
1 files changed, 214 insertions, 72 deletions
diff --git a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
index cd38b0a6e9..424e869d98 100644
--- a/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
+++ b/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
@@ -1,4 +1,5 @@
// 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>
@@ -30,7 +31,14 @@ public slots:
void init();
private Q_SLOTS:
- void consistent();
+ void unsignedIntegerConsistency_data();
+ void unsignedIntegerConsistency();
+ void signedIntegerConsistency_data();
+ void signedIntegerConsistency();
+ 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();
@@ -61,99 +69,233 @@ private Q_SLOTS:
#endif
};
-void tst_QHashFunctions::consistent()
+void tst_QHashFunctions::initTestCase()
{
- // QString-like
- const QString s = QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16);
- QCOMPARE(qHash(s, seed), qHash(QStringView(s), seed));
+ QTest::addColumn<quint64>("seedValue");
- // unsigned integers
- {
- constexpr unsigned char ae = 0xE4; // LATIN SMALL LETTER A WITH DIAERESIS
- const auto h8 = qHash(quint8(ae), seed);
- const auto h16 = qHash(quint16(ae), seed);
- const auto h32 = qHash(quint32(ae), seed);
- const auto h64 = qHash(quint64(ae), seed);
- QCOMPARE(h8, h16);
- QCOMPARE(h16, h32);
- QCOMPARE(h32, h64);
- // there are a few more unsigned types:
+ 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);
+}
+
+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);
+
+ // there are a few more unsigned types:
#ifdef __cpp_char8_t
- const auto hc8 = qHash(char8_t(ae), seed);
+ const auto hc8 = qHash(char8_t(value), seed);
#endif
- const auto hc16 = qHash(char16_t(ae), seed);
- const auto hc32 = qHash(char32_t(ae), seed);
+ const auto hc16 = qHash(char16_t(value), seed);
+ const auto hc32 = qHash(char32_t(value), seed);
#ifdef __cpp_char8_t
- QCOMPARE(hc8, h8);
+ QCOMPARE(hc8, hu8);
#endif
- QCOMPARE(hc16, h16);
- QCOMPARE(hc32, h32);
+ 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))
+ QCOMPARE(hs64, hs32);
}
- // signed integers
- {
- constexpr signed char ae = 0xE4; // LATIN SMALL LETTER A WITH DIAERESIS
- const auto h8 = qHash(qint8(ae), seed);
- const auto h16 = qHash(qint16(ae), seed);
- const auto h32 = qHash(qint32(ae), seed);
- const auto h64 = qHash(qint64(ae), seed);
- QCOMPARE(h8, h16);
- QCOMPARE(h16, h32);
- if constexpr (sizeof(size_t) == sizeof(int)) // 32-bit
- QEXPECT_FAIL("", "QTBUG-116080", Continue);
- QCOMPARE(h32, h64);
+ 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
}
+}
- // mixed signed/unsigned
- {
- const auto hu8 = qHash(quint8(42), seed);
- const auto hs8 = qHash(qint8(42), seed);
- QCOMPARE(hu8, hs8);
+void tst_QHashFunctions::floatingPointConsistency_data()
+{
+ QTest::addColumn<double>("value");
+ QTest::addRow("zero") << 0.0;
- const auto hu16 = qHash(quint16(4242), seed);
- const auto hs16 = qHash(qint16(4242), seed);
- QCOMPARE(hu16, hs16);
+ QTest::addRow("1.0") << 1.0;
+ QTest::addRow("infinity") << std::numeric_limits<double>::infinity();
- const auto hu32 = qHash(quint32(4242'4242), seed);
- const auto hs32 = qHash(qint32(4242'4242), seed);
- QCOMPARE(hu32, hs32);
+ 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());
- const auto hu64 = qHash(quint64(4242'424242), seed);
- const auto hs64 = qHash(qint64(4242'424242), seed);
- QCOMPARE(hu64, hs64);
- }
+ 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());
- // floats
- {
- const/*expr broken: QTBUG-116079*/ qfloat16 f16 = qfloat16(-42.f);
- const auto h16 = qHash(f16, seed);
- const auto h32 = qHash(float(f16), seed);
- const auto h64 = qHash(double(f16), seed);
- QCOMPARE(h16, h32);
- QEXPECT_FAIL("", "QTBUG-116077", Continue);
- QCOMPARE(h32, h64);
- }
+ 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::initTestCase()
+void tst_QHashFunctions::floatingPointConsistency()
{
- QTest::addColumn<quint64>("seedValue");
+ 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);
+ }
- 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;
+ // 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::init()
+void tst_QHashFunctions::stringConsistency_data()
{
- QFETCH_GLOBAL(quint64, seedValue);
- seed = size_t(seedValue);
+ QTest::addColumn<QString>("value");
+ QTest::newRow("null") << QString();
+ QTest::newRow("empty") << "";
+ QTest::newRow("withnull") << QStringLiteral("A\0z");
+ QTest::newRow("short-ascii") << "Hello";
+ QTest::newRow("long-ascii") << QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16);
+
+ QTest::newRow("short-latin1") << "Bokmål";
+ 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));
}
void tst_QHashFunctions::qhash()