summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2021-04-01 23:48:21 -0700
committerThiago Macieira <thiago.macieira@intel.com>2021-05-23 12:08:42 -0700
commit7ac0621ad1a649254e7d6175205e7ea22290b4d0 (patch)
tree095be248d129d62624b28908ddc4e2673c0ef9c3 /tests/auto/corelib/tools
parentffe5f925469aa1f824b3b3aa5ce4831ea2b0a19e (diff)
Introduce QHashSeed and switch to size_t seeds
Commit 37e0953613ef9a3db137bc8d3076441d9ae317d9 added a to-do, but we can actually change the type, since we've documented since Qt 5.10 that setting a non-zero value (aside from -1) with qSetGlobalQHashSeed was not allowed. Storing a value to be reset later is simply not supported. Change-Id: Id2983978ad544ff79911fffd1671f7b5de284bab Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Diffstat (limited to 'tests/auto/corelib/tools')
-rw-r--r--tests/auto/corelib/tools/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/tools/qhashseed/CMakeLists.txt14
-rw-r--r--tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp188
-rw-r--r--tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp39
4 files changed, 242 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/CMakeLists.txt b/tests/auto/corelib/tools/CMakeLists.txt
index a7d3889251..8b6723874b 100644
--- a/tests/auto/corelib/tools/CMakeLists.txt
+++ b/tests/auto/corelib/tools/CMakeLists.txt
@@ -16,6 +16,7 @@ add_subdirectory(qflatmap)
add_subdirectory(qfreelist)
add_subdirectory(qhash)
add_subdirectory(qhashfunctions)
+add_subdirectory(qhashseed)
add_subdirectory(qline)
add_subdirectory(qlist)
add_subdirectory(qmakearray)
diff --git a/tests/auto/corelib/tools/qhashseed/CMakeLists.txt b/tests/auto/corelib/tools/qhashseed/CMakeLists.txt
new file mode 100644
index 0000000000..bc40c63b3e
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/CMakeLists.txt
@@ -0,0 +1,14 @@
+#####################################################################
+## tst_qhashseed Test:
+#####################################################################
+
+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..1e3a7572d0
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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$
+**
+****************************************************************************/
+
+#include <QTest>
+
+#include <qhashfunctions.h>
+#include <qprocess.h>
+
+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()
+{
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+ 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()
+{
+ 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);
+}
+
+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()
+{
+ constexpr int Iterations = 16;
+ int oneThird = 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;
+ }
+
+ // report out
+ qInfo() << "Number of seeds with at least one third of the bits set:"
+ << oneThird << '/' << Iterations;
+ qInfo() << "Number of bits in OR'ed value:" << qPopulationCount(quintptr(ored))
+ << '/' << std::numeric_limits<size_t>::digits;
+ if (std::numeric_limits<size_t>::digits > 32) {
+ quint32 upper = quint64(ored) >> 32;
+ qInfo() << "Number of bits in the upper half:" << qPopulationCount(upper) << "/ 32";
+ QVERIFY(qPopulationCount(upper) > (32/3));
+ }
+
+ // at least one third of the seeds must have one third of all the bits set
+ QVERIFY(oneThird > (16/3));
+}
+
+#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..752228e5a1
--- /dev/null
+++ b/tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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$
+**
+****************************************************************************/
+
+#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;
+}