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));
67 hegel::internal::json::json tagged =
68 hegel::internal::json::json::array();
69 for (
size_t i = 0; i < basics.size(); ++i) {
70 hegel::internal::json::json elements =
71 hegel::internal::json::json::array();
72 elements.push_back(hegel::internal::json::json{
73 {
"type",
"constant"}, {
"value", (int64_t)i}});
74 elements.push_back(basics[i].schema);
75 tagged.push_back(hegel::internal::json::json{
76 {
"type",
"tuple"}, {
"elements", elements}});
78 hegel::internal::json::json schema = {{
"type",
"one_of"},
79 {
"generators", tagged}};
81 return BasicGenerator<T>{
83 [basics = std::move(basics)](
84 const hegel::internal::json::json_raw_ref& raw) -> T {
85 size_t idx =
static_cast<size_t>(raw[0].get_int64_t());
86 return basics[idx].parse_raw(raw[1]);
90 T do_draw(
const TestCase& tc)
const override {
91 if (
auto basic = as_basic()) {
92 return basic->do_draw(tc);
94 auto idx = integers<size_t>(
95 {.min_value = 0, .max_value = gens_.size() - 1})
97 return gens_[idx].do_draw(tc);
101 std::vector<Generator<T>> gens_;
120 template <
typename T>
122 return Generator<T>(
new SampledFromGenerator<T>(elements));
131 template <
typename T>
141 inline Generator<std::string>
143 std::vector<std::string> strings;
144 strings.reserve(elements.size());
145 for (
const char* s : elements) {
146 strings.push_back(s);
173 return Generator<T>(
new OneOfGenerator<T>(std::move(gens)));
182 template <
typename T>
190 template <
typename Variant,
typename GenTuple,
size_t I = 0>
191 Variant draw_variant_impl(
const GenTuple& gens,
size_t idx,
193 if constexpr (I < std::tuple_size_v<GenTuple>) {
195 return std::get<I>(gens).do_draw(tc);
197 return draw_variant_impl<Variant, GenTuple, I + 1>(gens, idx,
204 template <
typename Variant,
typename Parsers,
size_t I = 0>
206 parse_variant_impl(
const Parsers& parsers,
size_t idx,
207 const hegel::internal::json::json_raw_ref& raw) {
208 if constexpr (I < std::tuple_size_v<Parsers>) {
210 return Variant{std::in_place_index<I>,
211 std::get<I>(parsers)(raw)};
213 return parse_variant_impl<Variant, Parsers, I + 1>(parsers, idx,
225 template <
typename... Ts>
226 class VariantGenerator :
public IGenerator<std::variant<Ts...>> {
228 using Result = std::variant<Ts...>;
230 explicit VariantGenerator(Generator<Ts>... gens)
231 : gens_(std::move(gens)...) {}
233 std::optional<BasicGenerator<Result>> as_basic()
const override {
234 auto basics = std::apply(
235 [](
const auto&... g) {
236 return std::make_tuple(g.as_basic()...);
239 bool all_basic = std::apply(
240 [](
const auto&... b) {
return (b.has_value() && ...); },
245 hegel::internal::json::json tagged =
246 hegel::internal::json::json::array();
249 [&tagged, &i](
const auto&... b) {
250 ((tagged.push_back(hegel::internal::json::json{
252 {
"elements", hegel::internal::json::json::array(
253 {hegel::internal::json::json{
254 {
"type",
"constant"},
255 {
"value", (int64_t)i}},
262 hegel::internal::json::json schema = {{
"type",
"one_of"},
263 {
"generators", tagged}};
265 auto parsers = std::apply(
266 [](
const auto&... b) {
return std::make_tuple(b->parse...); },
269 return BasicGenerator<Result>{
271 [parsers = std::move(parsers)](
272 const hegel::internal::json::json_raw_ref& raw) -> Result {
273 size_t idx =
static_cast<size_t>(raw[0].get_int64_t());
274 return detail::parse_variant_impl<Result,
276 parsers, idx, raw[1]);
280 Result do_draw(
const TestCase& tc)
const override {
281 if (
auto basic = as_basic()) {
282 return basic->do_draw(tc);
284 constexpr size_t N =
sizeof...(Ts);
286 integers<size_t>({.min_value = 0, .max_value = N - 1});
287 size_t idx = index_gen.do_draw(tc);
288 return detail::draw_variant_impl<Result, decltype(gens_)>(gens_,
293 std::tuple<Generator<Ts>...> gens_;
299 template <
typename T>
300 class OptionalGenerator :
public IGenerator<std::optional<T>> {
302 explicit OptionalGenerator(Generator<T> gen) : gen_(std::move(gen)) {}
304 std::optional<BasicGenerator<std::optional<T>>>
305 as_basic()
const override {
306 auto basic = gen_.as_basic();
310 hegel::internal::json::json generators =
311 hegel::internal::json::json::array();
312 generators.push_back(hegel::internal::json::json{{
"type",
"null"}});
313 generators.push_back(basic->schema);
314 hegel::internal::json::json schema = {{
"type",
"one_of"},
315 {
"generators", generators}};
317 auto parse = basic->parse;
318 return BasicGenerator<std::optional<T>>{
320 [parse = std::move(parse)](
321 const hegel::internal::json::json_raw_ref& raw)
322 -> std::optional<T> {
330 std::optional<T> do_draw(
const TestCase& tc)
const override {
331 if (
auto basic = as_basic()) {
332 return basic->do_draw(tc);
334 bool is_none =
booleans().do_draw(tc);
338 return gen_.do_draw(tc);
360 template <
typename... Ts>
363 new VariantGenerator<Ts...>(std::move(gens)...));
381 template <
typename T>
384 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:121
Generator< bool > booleans()
Generate random boolean values.
Generator< std::variant< Ts... > > variant(Generator< Ts >... gens)
Generate std::variant from heterogeneous generators.
Definition combinators.h:361
Generator< std::optional< T > > optional(Generator< T > gen)
Generate optional values (present or absent).
Definition combinators.h:382
Generator< T > one_of(std::vector< Generator< T > > gens)
Choose from multiple generators of the same type.
Definition combinators.h:172