Refactor implementation of hashed random order test sorting

This commit is contained in:
Martin Hořeňovský 2020-04-14 16:39:45 +02:00
parent a2fc7cf8c0
commit bad0fb51f8
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A

View File

@ -16,63 +16,75 @@
#include "catch_test_case_info.h" #include "catch_test_case_info.h"
#include <algorithm> #include <algorithm>
#include <iterator>
#include <random>
#include <sstream> #include <sstream>
namespace Catch { namespace Catch {
struct HashTest { namespace {
explicit HashTest( Catch::SimplePcg32& rng ) { struct TestHasher {
basis = rng(); explicit TestHasher(Catch::SimplePcg32& rng) {
basis <<= 32; basis = rng();
basis |= rng(); basis <<= 32;
} basis |= rng();
uint64_t basis;
uint64_t operator()( TestCase const& t ) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for( const char c : t.name ) {
hash ^= c;
hash *= prime;
} }
return hash;
} uint64_t basis;
};
uint64_t operator()(TestCase const& t) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for (const char c : t.name) {
hash ^= c;
hash *= prime;
}
return hash;
}
};
} // end unnamed namespace
std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
switch( config.runOrder() ) { switch( config.runOrder() ) {
case RunTests::InDeclarationOrder:
// already in declaration order
break;
case RunTests::InLexicographicalOrder: { case RunTests::InLexicographicalOrder: {
std::vector<TestCase> sorted = unsortedTestCases; std::vector<TestCase> sorted = unsortedTestCases;
std::sort( sorted.begin(), sorted.end() ); std::sort( sorted.begin(), sorted.end() );
return sorted; return sorted;
} }
case RunTests::InRandomOrder: { case RunTests::InRandomOrder: {
seedRng( config ); seedRng( config );
HashTest h( rng() ); TestHasher h( rng() );
std::vector<std::tuple<uint64_t, std::string, TestCase const*>> indexed_tests;
using hashedTest = std::pair<uint64_t, TestCase const*>;
std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() ); indexed_tests.reserve( unsortedTestCases.size() );
std::transform( unsortedTestCases.begin(), unsortedTestCases.end(),
std::back_inserter( indexed_tests ), for (auto const& testCase : unsortedTestCases) {
[&]( TestCase const& t ) { indexed_tests.emplace_back(h(testCase), &testCase);
return std::make_tuple( h(t), t.name, &t ); }
} );
std::sort( indexed_tests.begin(), indexed_tests.end() ); std::sort(indexed_tests.begin(), indexed_tests.end(),
[](hashedTest const& lhs, hashedTest const& rhs) {
if (lhs.first == rhs.first) {
return lhs.second->name < rhs.second->name;
}
return lhs.first < rhs.first;
});
std::vector<TestCase> sorted; std::vector<TestCase> sorted;
sorted.reserve( unsortedTestCases.size() ); sorted.reserve( indexed_tests.size() );
std::transform( indexed_tests.begin(), indexed_tests.end(),
std::back_inserter( sorted ), for (auto const& hashed : indexed_tests) {
[]( std::tuple<uint64_t, std::string, TestCase const*> const& t ) { sorted.emplace_back(*hashed.second);
return *std::get<2>( t ); }
} );
return sorted; return sorted;
} }
case RunTests::InDeclarationOrder:
// already in declaration order
break;
} }
return unsortedTestCases; return unsortedTestCases;
} }