6#include "hegel/generators/numeric.h"
7#include "hegel/generators/primitives.h"
15 template <
typename T>
class SampledFromGenerator :
public IGenerator<T> {
17 explicit SampledFromGenerator(std::vector<T> elements)
18 : elements_(std::move(elements)) {
19 if (elements_.empty()) {
20 throw std::invalid_argument(
21 "sampled_from requires a non-empty vector");
25 std::optional<BasicGenerator<T>> as_basic()
const override {
26 hegel::internal::json::json schema = {
29 {
"max_value",
static_cast<int64_t
>(elements_.size() - 1)}};
30 auto elements = elements_;
31 return BasicGenerator<T>{
33 [elements = std::move(elements)](
34 const hegel::internal::json::json_raw_ref& raw) {
35 return elements[
static_cast<size_t>(raw.get_int64_t())];
40 std::vector<T> elements_;
45 template <
typename T>
class OneOfGenerator :
public IGenerator<T> {
47 explicit OneOfGenerator(std::vector<Generator<T>> gens)
48 : gens_(std::move(gens)) {
50 throw std::invalid_argument(
51 "one_of requires a non-empty vector of generators");
55 std::optional<BasicGenerator<T>> as_basic()
const override {
56 std::vector<BasicGenerator<T>> basics;
57 basics.reserve(gens_.size());
58 for (
const auto& gen : gens_) {
59 auto b = gen.as_basic();
62 basics.push_back(std::move(*b));
70 hegel::internal::json::json children =
71 hegel::internal::json::json::array();
72 for (
const auto& b : basics) {
73 children.push_back(b.schema);
75 hegel::internal::json::json schema = {{
"type",
"one_of"},
76 {
"generators", children}};
78 return BasicGenerator<T>{
80 [basics = std::move(basics)](
81 const hegel::internal::json::json_raw_ref& raw) -> T {
82 size_t idx =
static_cast<size_t>(raw[0].get_int64_t());
83 return basics[idx].parse_raw(raw[1]);
87 T do_draw(
const TestCase& tc)
const override {
88 if (
auto basic = as_basic()) {
89 return basic->do_draw(tc);
91 auto idx = integers<size_t>(
92 {.min_value = 0, .max_value = gens_.size() - 1})
94 return gens_[idx].do_draw(tc);
98 std::vector<Generator<T>> gens_;
117 template <
typename T>
119 return Generator<T>(
new SampledFromGenerator<T>(elements));
128 template <
typename T>
138 inline Generator<std::string>
140 std::vector<std::string> strings;
141 strings.reserve(elements.size());
142 for (
const char* s : elements) {
143 strings.push_back(s);
170 return Generator<T>(
new OneOfGenerator<T>(std::move(gens)));
179 template <
typename T>
187 template <
typename Variant,
typename GenTuple,
size_t I = 0>
188 Variant draw_variant_impl(
const GenTuple& gens,
size_t idx,
190 if constexpr (I < std::tuple_size_v<GenTuple>) {
192 return std::get<I>(gens).do_draw(tc);
194 return draw_variant_impl<Variant, GenTuple, I + 1>(gens, idx,
201 template <
typename Variant,
typename Parsers,
size_t I = 0>
203 parse_variant_impl(
const Parsers& parsers,
size_t idx,
204 const hegel::internal::json::json_raw_ref& raw) {
205 if constexpr (I < std::tuple_size_v<Parsers>) {
207 return Variant{std::in_place_index<I>,
208 std::get<I>(parsers)(raw)};
210 return parse_variant_impl<Variant, Parsers, I + 1>(parsers, idx,
223 template <
typename... Ts>
224 class VariantGenerator :
public IGenerator<std::variant<Ts...>> {
226 using Result = std::variant<Ts...>;
228 explicit VariantGenerator(Generator<Ts>... gens)
229 : gens_(std::move(gens)...) {}
231 std::optional<BasicGenerator<Result>> as_basic()
const override {
232 auto basics = std::apply(
233 [](
const auto&... g) {
234 return std::make_tuple(g.as_basic()...);
237 bool all_basic = std::apply(
238 [](
const auto&... b) {
return (b.has_value() && ...); },
245 hegel::internal::json::json children =
246 hegel::internal::json::json::array();
248 [&children](
const auto&... b) {
249 (children.push_back(b->schema), ...);
253 hegel::internal::json::json schema = {{
"type",
"one_of"},
254 {
"generators", children}};
256 auto parsers = std::apply(
257 [](
const auto&... b) {
return std::make_tuple(b->parse...); },
260 return BasicGenerator<Result>{
262 [parsers = std::move(parsers)](
263 const hegel::internal::json::json_raw_ref& raw) -> Result {
264 size_t idx =
static_cast<size_t>(raw[0].get_int64_t());
265 return detail::parse_variant_impl<Result,
267 parsers, idx, raw[1]);
271 Result do_draw(
const TestCase& tc)
const override {
272 if (
auto basic = as_basic()) {
273 return basic->do_draw(tc);
275 constexpr size_t N =
sizeof...(Ts);
277 integers<size_t>({.min_value = 0, .max_value = N - 1});
278 size_t idx = index_gen.do_draw(tc);
279 return detail::draw_variant_impl<Result, decltype(gens_)>(gens_,
284 std::tuple<Generator<Ts>...> gens_;
290 template <
typename T>
291 class OptionalGenerator :
public IGenerator<std::optional<T>> {
293 explicit OptionalGenerator(Generator<T> gen) : gen_(std::move(gen)) {}
295 std::optional<BasicGenerator<std::optional<T>>>
296 as_basic()
const override {
297 auto basic = gen_.as_basic();
301 hegel::internal::json::json generators =
302 hegel::internal::json::json::array();
303 generators.push_back(hegel::internal::json::json{
304 {
"type",
"constant"}, {
"value",
nullptr}});
305 generators.push_back(basic->schema);
306 hegel::internal::json::json schema = {{
"type",
"one_of"},
307 {
"generators", generators}};
309 auto parse = basic->parse;
310 return BasicGenerator<std::optional<T>>{
312 [parse = std::move(parse)](
313 const hegel::internal::json::json_raw_ref& raw)
314 -> std::optional<T> {
317 size_t idx =
static_cast<size_t>(raw[0].get_int64_t());
321 return parse(raw[1]);
325 std::optional<T> do_draw(
const TestCase& tc)
const override {
326 if (
auto basic = as_basic()) {
327 return basic->do_draw(tc);
329 bool is_none =
booleans().do_draw(tc);
333 return gen_.do_draw(tc);
355 template <
typename... Ts>
358 new VariantGenerator<Ts...>(std::move(gens)...));
376 template <
typename T>
379 new OptionalGenerator<T>(std::move(gen)));
Handle to the currently-executing test case.
Definition test_case.h:34
The base class of all generators.
Definition core.h:157
Hegel generators.
Definition core.h:16
Generator< T > sampled_from(const std::vector< T > &elements)
Sample from a fixed set of values.
Definition combinators.h:118
Generator< bool > booleans()
Generate random boolean values.
Generator< std::variant< Ts... > > variant(Generator< Ts >... gens)
Generate std::variant from heterogeneous generators.
Definition combinators.h:356
Generator< std::optional< T > > optional(Generator< T > gen)
Generate optional values (present or absent).
Definition combinators.h:377
Generator< T > one_of(std::vector< Generator< T > > gens)
Choose from multiple generators of the same type.
Definition combinators.h:169