I try to implement a generator in catch2 of an std::array of 1024 random values. Below my code
#include "catch2/catch_all.hpp"
#include <array>
#include <vector>
TEST_CASE("Foo") {
auto s = GENERATE(as<std::array<char, 1024> >{}, 'a');
REQUIRE(!s.empty());
}
The following error is generated
In file included from /opt/compiler-explorer/libs/catch2/v3.0.0-preview3/src/catch2/generators/catch_generators_all.hpp:25,
from /opt/compiler-explorer/libs/catch2/v3.0.0-preview3/src/catch2/catch_all.hpp:46,
from <source>:1:
/opt/compiler-explorer/libs/catch2/v3.0.0-preview3/src/catch2/generators/catch_generators.hpp: In instantiation of 'Catch::Generators::Generators<T> Catch::Generators::makeGenerators(as<T>, U&&, Gs&& ...) [with T = std::array<char, 1024>; U = char; Gs = {}]':
<source>:7:14: required from here
/opt/compiler-explorer/libs/catch2/v3.0.0-preview3/src/catch2/generators/catch_generators.hpp:181:39: error: array must be initialized with a brace-enclosed initializer
181 | return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
Any idea how to overcome this issue?
Documentation how to provide custom generators in Catch2 sucks. Had to review Catch2 code to figure out how other generators are implemented and got this:
template <typename T, typename Dist>
struct FillRandomGenerator : Catch::Generators::IGenerator<T> {
template <typename D>
explicit FillRandomGenerator(size_t repeatCount, D&& dist)
: repeatCount { repeatCount }
, distr { std::forward<D>(dist) }
{
fillRandom();
}
T value;
size_t repeatCount;
Dist distr;
std::default_random_engine randGen {};
bool next() override
{
fillRandom();
return --repeatCount;
}
T const& get() const override
{
return value;
}
void fillRandom()
{
std::generate(std::begin(value), std::end(value), [&]() { return distr(randGen); });
}
};
template <typename T, typename Dist>
Catch::Generators::GeneratorWrapper<T> fillRandom(size_t repeatCount, Dist&& distr)
{
return Catch::Generators::GeneratorWrapper<T>(Catch::Detail::make_unique<FillRandomGenerator<T, std::decay_t<Dist>>>(repeatCount, std::forward<Dist>(distr)));
}
https://godbolt.org/z/jfzT15Tcv
There is lots of room for improvement, but general idea should be clear.
With current implementation works only for std::array
, other containers will remain empty.
I do not like that I had to use Catch::Detail::make_unique
. Detail
usually means user of library should not touch symbols in this namespace since. symbols there can change without any warning in next release.