Hegel 0.3.5
Property-based testing for C++
Loading...
Searching...
No Matches
default.h
1#pragma once
2
3#include <map>
4#include <optional>
5#include <set>
6#include <variant>
7#include <vector>
8
9#include <rfl.hpp>
10
11#include "hegel/core.h"
12#include "hegel/generators/builds.h"
13#include "hegel/generators/collections.h"
14#include "hegel/generators/combinators.h"
15#include "hegel/generators/numeric.h"
16#include "hegel/generators/primitives.h"
17#include "hegel/generators/strings.h"
18
19namespace hegel::generators {
20
23
24 template <typename T> class DerivedGenerator;
25
26 // Forward declaration — defined below after all specializations
27 template <typename T> DerivedGenerator<T> default_generator();
28
30 namespace detail {
31
32 // =================================================================
33 // Type traits for container detection
34 // =================================================================
35
36 template <typename T> struct is_vector : std::false_type {};
37 template <typename T>
38 struct is_vector<std::vector<T>> : std::true_type {};
39
40 template <typename T> struct is_set : std::false_type {};
41 template <typename T> struct is_set<std::set<T>> : std::true_type {};
42
43 template <typename T> struct is_map : std::false_type {};
44 template <typename K, typename V>
45 struct is_map<std::map<K, V>> : std::true_type {};
46
47 template <typename T> struct is_optional : std::false_type {};
48 template <typename T>
49 struct is_optional<std::optional<T>> : std::true_type {};
50
51 template <typename T> struct is_tuple : std::false_type {};
52 template <typename... Ts>
53 struct is_tuple<std::tuple<Ts...>> : std::true_type {};
54
55 template <typename T> struct is_variant : std::false_type {};
56 template <typename... Ts>
57 struct is_variant<std::variant<Ts...>> : std::true_type {};
58
59 // =================================================================
60 // Reflectable struct detection
61 // =================================================================
62
63 template <typename T, typename = void>
64 struct is_reflectable_struct : std::false_type {};
65
66 template <typename T>
67 struct is_reflectable_struct<
68 T, std::void_t<decltype(rfl::to_view(std::declval<T&>()))>>
69 : std::true_type {};
70
71 // =================================================================
72 // DefaultGenerator trait — primary template (struct fallback)
73 // =================================================================
74
75 template <typename T, typename Enable = void> struct DefaultGenerator {
76 static_assert(
77 is_reflectable_struct<T>::value,
78 "default_generator<T>(): T must be a supported primitive, "
79 "container, or reflectable struct");
80
81 static Generator<T> generator() {
82 return compose([](const TestCase& tc) -> T {
83 T result{};
84 auto view = rfl::to_view(result);
85 view.apply([&tc](const auto& field) {
86 using PtrType =
87 typename std::remove_cvref_t<decltype(field)>::Type;
88 using FieldType = std::remove_pointer_t<PtrType>;
89 *field.value() =
90 default_generator<FieldType>().do_draw(tc);
91 });
92 return result;
93 });
94 }
95 };
96
97 // =================================================================
98 // Specializations for primitive types
99 // =================================================================
100
101 template <> struct DefaultGenerator<bool> {
102 static Generator<bool> generator() { return booleans(); }
103 };
104
105 template <> struct DefaultGenerator<std::string> {
106 static Generator<std::string> generator() { return text(); }
107 };
108
109 template <> struct DefaultGenerator<std::monostate> {
110 static Generator<std::monostate> generator() {
111 return just(std::monostate{});
112 }
113 };
114
115 template <typename T>
116 struct DefaultGenerator<T, std::enable_if_t<std::is_integral_v<T> &&
117 !std::is_same_v<T, bool>>> {
118 static Generator<T> generator() { return integers<T>(); }
119 };
120
121 template <typename T>
122 struct DefaultGenerator<T,
123 std::enable_if_t<std::is_floating_point_v<T>>> {
124 static Generator<T> generator() { return floats<T>(); }
125 };
126
127 // =================================================================
128 // Specializations for standard containers
129 // =================================================================
130
131 template <typename T>
132 struct DefaultGenerator<T, std::enable_if_t<is_vector<T>::value>> {
133 static Generator<T> generator() {
134 using Elem = typename T::value_type;
135 return vectors(default_generator<Elem>());
136 }
137 };
138
139 template <typename T>
140 struct DefaultGenerator<T, std::enable_if_t<is_set<T>::value>> {
141 static Generator<T> generator() {
142 using Elem = typename T::value_type;
143 return sets(default_generator<Elem>());
144 }
145 };
146
147 template <typename T>
148 struct DefaultGenerator<T, std::enable_if_t<is_map<T>::value>> {
149 static Generator<T> generator() {
150 using K = typename T::key_type;
151 using V = typename T::mapped_type;
152 return maps(default_generator<K>(), default_generator<V>());
153 }
154 };
155
156 template <typename T>
157 struct DefaultGenerator<T, std::enable_if_t<is_optional<T>::value>> {
158 static Generator<T> generator() {
159 using Inner = typename T::value_type;
160 return optional(default_generator<Inner>());
161 }
162 };
163
164 // --- std::tuple<Ts...> ---
165
166 template <typename Tuple, size_t... Is>
167 auto make_default_tuple_gen(std::index_sequence<Is...>) {
168 return tuples(
169 default_generator<std::tuple_element_t<Is, Tuple>>()...);
170 }
171
172 template <typename T>
173 struct DefaultGenerator<T, std::enable_if_t<is_tuple<T>::value>> {
174 static Generator<T> generator() {
175 return make_default_tuple_gen<T>(
176 std::make_index_sequence<std::tuple_size_v<T>>{});
177 }
178 };
179
180 // --- std::variant<Ts...> ---
181
182 template <typename Variant, size_t... Is>
183 auto make_default_variant_gen(std::index_sequence<Is...>) {
184 return variant(default_generator<
185 std::variant_alternative_t<Is, Variant>>()...);
186 }
187
188 template <typename T>
189 struct DefaultGenerator<T, std::enable_if_t<is_variant<T>::value>> {
190 static Generator<T> generator() {
191 return make_default_variant_gen<T>(
192 std::make_index_sequence<std::variant_size_v<T>>{});
193 }
194 };
195
196 } // namespace detail
198
199 // =============================================================================
200 // Public API
201 // =============================================================================
202
217 template <typename T> class DerivedGenerator : public Generator<T> {
218 public:
220 DerivedGenerator(Generator<T> base) : Generator<T>(std::move(base)) {}
222
240 template <typename... Fields>
241 DerivedGenerator<T> override(Fields... fields) const {
242 Generator<T> base = *this;
243 auto fields_tuple = std::make_tuple(std::move(fields)...);
244 return DerivedGenerator<T>(
245 compose([base, fields_tuple](const TestCase& tc) mutable -> T {
246 T result = base.do_draw(tc);
247 std::apply(
248 [&result, &tc](auto&... fs) {
249 ((result.*(std::remove_reference_t<
250 decltype(fs)>::member_ptr) =
251 fs.generator.do_draw(tc)),
252 ...);
253 },
254 fields_tuple);
255 return result;
256 }));
257 }
258 };
259
283 template <typename T> DerivedGenerator<T> default_generator() {
284 return DerivedGenerator<T>(detail::DefaultGenerator<T>::generator());
285 }
286
288
289} // namespace hegel::generators
Handle to the currently-executing test case.
Definition test_case.h:34
A Generator produced by default_generator<T>().
Definition default.h:217
The base class of all generators.
Definition core.h:157
Hegel generators.
Definition core.h:16
Generator< std::tuple< Ts... > > tuples(Generator< Ts >... gens)
Generate tuples from multiple generators.
Definition collections.h:397
Generator< T > just(T value)
Generate a constant value.
Definition primitives.h:52
Generator< std::string > text(TextParams params={})
Generate random text strings.
Generator< std::vector< T > > vectors(Generator< T > elements, VectorsParams params={})
Generate vectors with elements from another generator.
Definition collections.h:256
Field< MemberPtr, Gen > field(Gen gen)
Create a field specification for builds_agg().
Definition builds.h:73
auto compose(F &&fn)
*‍/
Definition core.h:360
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< std::set< T > > sets(Generator< T > elements, SetsParams params={})
Generate sets with elements from another generator.
Definition collections.h:276
DerivedGenerator< T > default_generator()
Create a default generator for type T.
Definition default.h:283
Generator< std::map< K, V > > maps(Generator< K > keys, Generator< V > values, MapsParams params={})
Generate maps with configurable key and value types.
Definition collections.h:304