4#include <initializer_list>
13#include "hegel/core.h"
20 template <
typename T>
class SampledFromGenerator :
public IGenerator<T> {
22 explicit SampledFromGenerator(std::vector<T> elements)
23 : elements_(std::move(elements)) {
24 if (elements_.empty()) {
25 throw std::invalid_argument(
26 "sampled_from requires a non-empty vector");
30 T do_draw(
const TestCase& tc)
const override {
31 int64_t index = hegel::internal::draw_integer(
32 tc, 0,
static_cast<int64_t
>(elements_.size() - 1));
33 return elements_[
static_cast<size_t>(index)];
37 std::vector<T> elements_;
42 template <
typename T>
class OneOfGenerator :
public IGenerator<T> {
44 explicit OneOfGenerator(std::vector<Generator<T>> gens)
45 : gens_(std::move(gens)) {
47 throw std::invalid_argument(
48 "one_of requires a non-empty vector of generators");
52 T do_draw(
const TestCase& tc)
const override {
53 namespace hi = hegel::internal;
54 hi::start_span(tc, hi::SpanLabel::OneOf);
56 hi::draw_integer(tc, 0,
static_cast<int64_t
>(gens_.size() - 1));
57 T result = gens_[
static_cast<size_t>(index)].do_draw(tc);
63 std::vector<Generator<T>> gens_;
84 return Generator<T>(
new SampledFromGenerator<T>(elements));
103 inline Generator<std::string>
105 std::vector<std::string> strings;
106 strings.reserve(elements.size());
107 for (
const char* s : elements) {
108 strings.push_back(s);
135 return Generator<T>(
new OneOfGenerator<T>(std::move(gens)));
144 template <
typename T>
152 template <
typename Variant,
typename GenTuple,
size_t I = 0>
153 Variant draw_variant_impl(
const GenTuple& gens,
size_t idx,
155 if constexpr (I < std::tuple_size_v<GenTuple>) {
157 return Variant{std::in_place_index<I>,
158 std::get<I>(gens).do_draw(tc)};
160 return draw_variant_impl<Variant, GenTuple, I + 1>(gens, idx,
173 template <
typename... Ts>
174 class VariantGenerator :
public IGenerator<std::variant<Ts...>> {
176 using Result = std::variant<Ts...>;
178 explicit VariantGenerator(Generator<Ts>... gens)
179 : gens_(std::move(gens)...) {}
181 Result do_draw(
const TestCase& tc)
const override {
182 namespace hi = hegel::internal;
183 constexpr size_t N =
sizeof...(Ts);
184 hi::start_span(tc, hi::SpanLabel::OneOf);
186 hi::draw_integer(tc, 0,
static_cast<int64_t
>(N - 1));
187 Result result = detail::draw_variant_impl<Result, decltype(gens_)>(
188 gens_,
static_cast<size_t>(index), tc);
194 std::tuple<Generator<Ts>...> gens_;
199 template <
typename T>
200 class OptionalGenerator :
public IGenerator<std::optional<T>> {
202 explicit OptionalGenerator(Generator<T> gen) : gen_(std::move(gen)) {}
204 std::optional<T> do_draw(
const TestCase& tc)
const override {
205 namespace hi = hegel::internal;
206 hi::start_span(tc, hi::SpanLabel::Optional);
207 std::optional<T> result;
208 if (hi::draw_boolean(tc, 0.5)) {
209 result = gen_.do_draw(tc);
234 template <
typename... Ts>
237 new VariantGenerator<Ts...>(std::move(gens)...));
255 template <
typename T>
258 new OptionalGenerator<T>(std::move(gen)));
266 template <
typename T>
class DeferredGenerator :
public IGenerator<T> {
268 explicit DeferredGenerator(
269 std::shared_ptr<std::optional<Generator<T>>> slot)
270 : slot_(std::move(slot)) {}
272 T do_draw(
const TestCase& tc)
const override {
274 throw std::runtime_error(
275 "deferred generator drawn before set() was called");
277 return (*slot_)->do_draw(tc);
281 std::shared_ptr<std::optional<Generator<T>>> slot_;
296 template <
typename T>
class DeferredGeneratorDefinition {
298 DeferredGeneratorDefinition()
299 : slot_(std::make_shared<std::optional<
Generator<T>>>()) {}
324 throw std::runtime_error(
325 "deferred generator set() called more than once");
327 *slot_ = std::move(gen);
331 std::shared_ptr<std::optional<Generator<T>>> slot_;
Handle to the currently-executing test case.
Definition test_case.h:40
A forward reference to a generator whose definition is provided later.
Definition combinators.h:296
Generator< T > generator() const
Return a handle that delegates to whatever is later passed to set(). May be called multiple times....
Definition combinators.h:309
void set(Generator< T > gen)
Set the implementation for this deferred generator.
Definition combinators.h:322
The base class of all generators.
Definition core.h:67
Hegel generators.
Definition core.h:17
DeferredGeneratorDefinition< T > deferred()
Create a deferred generator definition for forward references.
Definition combinators.h:352
Generator< T > sampled_from(const std::vector< T > &elements)
Sample from a fixed set of values.
Definition combinators.h:83
Generator< std::variant< Ts... > > variant(Generator< Ts >... gens)
Generate std::variant from heterogeneous generators.
Definition combinators.h:235
Generator< std::optional< T > > optional(Generator< T > gen)
Generate optional values (present or absent).
Definition combinators.h:256
Generator< T > one_of(std::vector< Generator< T > > gens)
Choose from multiple generators of the same type.
Definition combinators.h:134
Base interface for generators.
Definition core.h:29