diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 957d3af21..2ac7f1b7e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -141,6 +141,7 @@ detect_stray_source_files("${libyul_sources}" "libyul/") set(yul_phaser_sources yulPhaser/Chromosome.cpp yulPhaser/Program.cpp + yulPhaser/Random.cpp # FIXME: yul-phaser is not a library so I can't just add it to target_link_libraries(). # My current workaround is just to include its source files here but this introduces diff --git a/test/yulPhaser/Random.cpp b/test/yulPhaser/Random.cpp new file mode 100644 index 000000000..c69b91055 --- /dev/null +++ b/test/yulPhaser/Random.cpp @@ -0,0 +1,95 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +using namespace std; + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(RandomTest) + +BOOST_AUTO_TEST_CASE(uniformRandomInt_returns_different_values_when_called_multiple_times) +{ + constexpr uint32_t numSamples = 1000; + constexpr uint32_t numOutcomes = 100; + + vector samples1; + vector samples2; + for (uint32_t i = 0; i < numSamples; ++i) + { + samples1.push_back(uniformRandomInt(0, numOutcomes - 1)); + samples2.push_back(uniformRandomInt(0, numOutcomes - 1)); + } + + vector counts1(numSamples, 0); + vector counts2(numSamples, 0); + for (uint32_t i = 0; i < numSamples; ++i) + { + ++counts1[samples1[i]]; + ++counts2[samples2[i]]; + } + + // This test rules out not only the possibility that the two sequences are the same but also + // that they're just different permutations of the same values. The test is probabilistic so + // it's technically possible for it to fail even if generator is good but the probability is + // so low that it would happen on average once very 10^125 billion years if you repeated it + // every second. The chance is much lower than 1 in 1000^100 / 100!. + // + // This does not really guarantee that the generated numbers have the right distribution or + // or that they don't come in long, repeating sequences but the implementation is very simple + // (it just calls a generator from boost) so our goal here is just to make sure it's used + // properly and we're not getting something totally non-random, e.g. the same number every time. + BOOST_TEST(counts1 != counts2); +} + +BOOST_AUTO_TEST_CASE(binomialRandomInt_returns_different_values_when_called_multiple_times) +{ + constexpr uint32_t numSamples = 1000; + constexpr uint32_t numTrials = 100; + constexpr double successProbability = 0.6; + + vector samples1; + vector samples2; + for (uint32_t i = 0; i < numSamples; ++i) + { + samples1.push_back(binomialRandomInt(numTrials, successProbability)); + samples2.push_back(binomialRandomInt(numTrials, successProbability)); + } + + vector counts1(numSamples, 0); + vector counts2(numSamples, 0); + for (uint32_t i = 0; i < numSamples; ++i) + { + ++counts1[samples1[i]]; + ++counts2[samples2[i]]; + } + + // See remark for uniformRandomInt() above. Same applies here. + BOOST_TEST(counts1 != counts2); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +}