diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2021-04-01 23:48:21 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2021-05-23 12:08:42 -0700 |
commit | 7ac0621ad1a649254e7d6175205e7ea22290b4d0 (patch) | |
tree | 095be248d129d62624b28908ddc4e2673c0ef9c3 /tests/auto/corelib/tools | |
parent | ffe5f925469aa1f824b3b3aa5ce4831ea2b0a19e (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.txt | 1 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhashseed/CMakeLists.txt | 14 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhashseed/tst_qhashseed.cpp | 188 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhashseed/tst_qhashseed_helper.cpp | 39 |
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; +} |