mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-12 21:02:38 -03:00
951870807e
0000ea3265
test: Add test for GetRandMillis and GetRandMicros (MarcoFalke)fa0e5b89cf
Add templated GetRandomDuration<> (MarcoFalke) Pull request description: A naive implementation of this template is dangerous, because the call site might accidentally omit the template parameter: ```cpp template <typename D> D GetRandDur(const D& duration_max) { return D{GetRand(duration_max.count())}; } BOOST_AUTO_TEST_CASE(util_time_GetRandTime) { std::chrono::seconds rand_hour = GetRandDur(std::chrono::hours{1}); // Want seconds to be in range [0..1hour), but always get zero :(((( BOOST_CHECK_EQUAL(rand_hour.count(), 0); } ``` Luckily `std::common_type` is already specialised in the standard lib for `std::chrono::duration` (https://en.cppreference.com/w/cpp/chrono/duration/common_type). And its effect seem to be that the call site must always specify the template argument explicitly. So instead of implementing the function for each duration type by hand, replace it with a templated version that is safe to use. ACKs for top commit: laanwj: Code review ACK0000ea3265
promag: Code review ACK0000ea3265
. jonatack: ACK0000ea3
thanks for the improved documentation. Code review, built, ran `src/test/test_bitcoin -t random_tests -l test_suite` for the new unit tests, `git diff fa05a4c 0000ea3` since previous review: hebasto: ACK0000ea3265
with non-blocking [nit](https://github.com/bitcoin/bitcoin/pull/18781#discussion_r424924671). Tree-SHA512: e89d46e31452be6ea14269ecbbb2cdd9ae83b4412cd14dff7d1084283092722a2f847cb501e8054394e4a3eff852f9c87f6d694fd008b3f7e8458cb5a3068af7
136 lines
5 KiB
C++
136 lines
5 KiB
C++
// Copyright (c) 2017-2020 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <random.h>
|
|
|
|
#include <test/util/setup_common.h>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <random>
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup)
|
|
|
|
BOOST_AUTO_TEST_CASE(osrandom_tests)
|
|
{
|
|
BOOST_CHECK(Random_SanityCheck());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(fastrandom_tests)
|
|
{
|
|
// Check that deterministic FastRandomContexts are deterministic
|
|
g_mock_deterministic_tests = true;
|
|
FastRandomContext ctx1(true);
|
|
FastRandomContext ctx2(true);
|
|
|
|
for (int i = 10; i > 0; --i) {
|
|
BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U});
|
|
BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006});
|
|
BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2917185654);
|
|
BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2144374);
|
|
}
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
|
|
BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17));
|
|
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
|
|
BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128));
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
|
|
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
|
|
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
|
|
|
|
// Check that a nondeterministic ones are not
|
|
g_mock_deterministic_tests = false;
|
|
for (int i = 10; i > 0; --i) {
|
|
BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U});
|
|
BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006});
|
|
BOOST_CHECK(GetRandMicros(std::chrono::hours{1}) != std::chrono::microseconds{2917185654});
|
|
BOOST_CHECK(GetRandMillis(std::chrono::hours{1}) != std::chrono::milliseconds{2144374});
|
|
}
|
|
{
|
|
FastRandomContext ctx3, ctx4;
|
|
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
|
|
}
|
|
{
|
|
FastRandomContext ctx3, ctx4;
|
|
BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
|
|
}
|
|
{
|
|
FastRandomContext ctx3, ctx4;
|
|
BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(fastrandom_randbits)
|
|
{
|
|
FastRandomContext ctx1;
|
|
FastRandomContext ctx2;
|
|
for (int bits = 0; bits < 63; ++bits) {
|
|
for (int j = 0; j < 1000; ++j) {
|
|
uint64_t rangebits = ctx1.randbits(bits);
|
|
BOOST_CHECK_EQUAL(rangebits >> bits, 0U);
|
|
uint64_t range = ((uint64_t)1) << bits | rangebits;
|
|
uint64_t rand = ctx2.randrange(range);
|
|
BOOST_CHECK(rand < range);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Does-it-compile test for compatibility with standard C++11 RNG interface. */
|
|
BOOST_AUTO_TEST_CASE(stdrandom_test)
|
|
{
|
|
FastRandomContext ctx;
|
|
std::uniform_int_distribution<int> distribution(3, 9);
|
|
for (int i = 0; i < 100; ++i) {
|
|
int x = distribution(ctx);
|
|
BOOST_CHECK(x >= 3);
|
|
BOOST_CHECK(x <= 9);
|
|
|
|
std::vector<int> test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
|
std::shuffle(test.begin(), test.end(), ctx);
|
|
for (int j = 1; j <= 10; ++j) {
|
|
BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
|
|
}
|
|
Shuffle(test.begin(), test.end(), ctx);
|
|
for (int j = 1; j <= 10; ++j) {
|
|
BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Test that Shuffle reaches every permutation with equal probability. */
|
|
BOOST_AUTO_TEST_CASE(shuffle_stat_test)
|
|
{
|
|
FastRandomContext ctx(true);
|
|
uint32_t counts[5 * 5 * 5 * 5 * 5] = {0};
|
|
for (int i = 0; i < 12000; ++i) {
|
|
int data[5] = {0, 1, 2, 3, 4};
|
|
Shuffle(std::begin(data), std::end(data), ctx);
|
|
int pos = data[0] + data[1] * 5 + data[2] * 25 + data[3] * 125 + data[4] * 625;
|
|
++counts[pos];
|
|
}
|
|
unsigned int sum = 0;
|
|
double chi_score = 0.0;
|
|
for (int i = 0; i < 5 * 5 * 5 * 5 * 5; ++i) {
|
|
int i1 = i % 5, i2 = (i / 5) % 5, i3 = (i / 25) % 5, i4 = (i / 125) % 5, i5 = i / 625;
|
|
uint32_t count = counts[i];
|
|
if (i1 == i2 || i1 == i3 || i1 == i4 || i1 == i5 || i2 == i3 || i2 == i4 || i2 == i5 || i3 == i4 || i3 == i5 || i4 == i5) {
|
|
BOOST_CHECK(count == 0);
|
|
} else {
|
|
chi_score += ((count - 100.0) * (count - 100.0)) / 100.0;
|
|
BOOST_CHECK(count > 50);
|
|
BOOST_CHECK(count < 150);
|
|
sum += count;
|
|
}
|
|
}
|
|
BOOST_CHECK(chi_score > 58.1411); // 99.9999% confidence interval
|
|
BOOST_CHECK(chi_score < 210.275);
|
|
BOOST_CHECK_EQUAL(sum, 12000U);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|