Skip to main content

hegel/generators/
default.rs

1use super::{
2    BoolGenerator, BoxedGenerator, CharactersGenerator, DurationGenerator, FloatGenerator,
3    Generator, HashMapGenerator, IntegerGenerator, OptionalGenerator, TextGenerator, VecGenerator,
4    booleans, characters, collections::ArrayGenerator, durations, floats, hashmaps, integers,
5    optional, text, vecs,
6};
7use std::collections::HashMap;
8use std::hash::Hash;
9use std::path::PathBuf;
10use std::time::Duration;
11
12/// Trait for types that have a default generator.
13///
14/// This is used by derive macros to automatically generate values for fields.
15pub trait DefaultGenerator: Sized {
16    type Generator: super::Generator<Self> + 'static;
17    fn default_generator() -> Self::Generator;
18}
19
20/// Create a generator for a type using its default generator.
21///
22/// This is the primary way to get a generator for types that implement
23/// [`DefaultGenerator`], including types with `#[derive(DefaultGenerator)]`.
24///
25/// # Example
26///
27/// ```no_run
28/// use hegel::generators::{self as gs, DefaultGenerator};
29/// use hegel::DefaultGenerator;
30///
31/// #[derive(DefaultGenerator, Debug)]
32/// struct Person {
33///     name: String,
34///     age: u32,
35/// }
36///
37/// #[hegel::test]
38/// fn my_test(tc: hegel::TestCase) {
39///     // Generate with defaults
40///     let person: Person = tc.draw(gs::default::<Person>());
41///
42///     // Customize field generators
43///     let person: Person = tc.draw(gs::default::<Person>()
44///         .age(gs::integers().min_value(0).max_value(120)));
45/// }
46/// ```
47pub fn default<T: DefaultGenerator>() -> T::Generator {
48    T::default_generator()
49}
50
51impl DefaultGenerator for bool {
52    type Generator = BoolGenerator;
53    fn default_generator() -> Self::Generator {
54        booleans()
55    }
56}
57
58impl DefaultGenerator for String {
59    type Generator = TextGenerator;
60    fn default_generator() -> Self::Generator {
61        text()
62    }
63}
64
65impl DefaultGenerator for char {
66    type Generator = CharactersGenerator;
67    fn default_generator() -> Self::Generator {
68        characters()
69    }
70}
71
72impl DefaultGenerator for i8 {
73    type Generator = IntegerGenerator<i8>;
74    fn default_generator() -> Self::Generator {
75        integers()
76    }
77}
78
79impl DefaultGenerator for i16 {
80    type Generator = IntegerGenerator<i16>;
81    fn default_generator() -> Self::Generator {
82        integers()
83    }
84}
85
86impl DefaultGenerator for i32 {
87    type Generator = IntegerGenerator<i32>;
88    fn default_generator() -> Self::Generator {
89        integers()
90    }
91}
92
93impl DefaultGenerator for i64 {
94    type Generator = IntegerGenerator<i64>;
95    fn default_generator() -> Self::Generator {
96        integers()
97    }
98}
99
100impl DefaultGenerator for u8 {
101    type Generator = IntegerGenerator<u8>;
102    fn default_generator() -> Self::Generator {
103        integers()
104    }
105}
106
107impl DefaultGenerator for u16 {
108    type Generator = IntegerGenerator<u16>;
109    fn default_generator() -> Self::Generator {
110        integers()
111    }
112}
113
114impl DefaultGenerator for u32 {
115    type Generator = IntegerGenerator<u32>;
116    fn default_generator() -> Self::Generator {
117        integers()
118    }
119}
120
121impl DefaultGenerator for u64 {
122    type Generator = IntegerGenerator<u64>;
123    fn default_generator() -> Self::Generator {
124        integers()
125    }
126}
127
128impl DefaultGenerator for i128 {
129    type Generator = IntegerGenerator<i128>;
130    fn default_generator() -> Self::Generator {
131        integers()
132    }
133}
134
135impl DefaultGenerator for u128 {
136    type Generator = IntegerGenerator<u128>;
137    fn default_generator() -> Self::Generator {
138        integers()
139    }
140}
141
142impl DefaultGenerator for isize {
143    type Generator = IntegerGenerator<isize>;
144    fn default_generator() -> Self::Generator {
145        integers()
146    }
147}
148
149impl DefaultGenerator for usize {
150    type Generator = IntegerGenerator<usize>;
151    fn default_generator() -> Self::Generator {
152        integers()
153    }
154}
155
156impl DefaultGenerator for f32 {
157    type Generator = FloatGenerator<f32>;
158    fn default_generator() -> Self::Generator {
159        floats()
160    }
161}
162
163impl DefaultGenerator for f64 {
164    type Generator = FloatGenerator<f64>;
165    fn default_generator() -> Self::Generator {
166        floats()
167    }
168}
169
170impl<T: DefaultGenerator + 'static> DefaultGenerator for Option<T>
171where
172    T::Generator: Send + Sync,
173{
174    type Generator = OptionalGenerator<T::Generator, T>;
175    fn default_generator() -> Self::Generator {
176        optional(T::default_generator())
177    }
178}
179
180impl<T: DefaultGenerator + 'static> DefaultGenerator for Vec<T>
181where
182    T::Generator: Send + Sync,
183{
184    type Generator = VecGenerator<T::Generator, T>;
185    fn default_generator() -> Self::Generator {
186        vecs(T::default_generator())
187    }
188}
189
190impl<T: DefaultGenerator + 'static, const N: usize> DefaultGenerator for [T; N]
191where
192    T::Generator: Send + Sync,
193{
194    type Generator = ArrayGenerator<T::Generator, T, N>;
195    fn default_generator() -> Self::Generator {
196        ArrayGenerator::new(T::default_generator())
197    }
198}
199
200impl DefaultGenerator for Duration {
201    type Generator = DurationGenerator;
202    fn default_generator() -> Self::Generator {
203        durations()
204    }
205}
206
207impl DefaultGenerator for PathBuf {
208    type Generator = BoxedGenerator<'static, PathBuf>;
209    fn default_generator() -> Self::Generator {
210        text().map(PathBuf::from).boxed()
211    }
212}
213
214impl<K: DefaultGenerator + 'static, V: DefaultGenerator + 'static> DefaultGenerator
215    for HashMap<K, V>
216where
217    K: Eq + Hash,
218    K::Generator: Send + Sync,
219    V::Generator: Send + Sync,
220{
221    type Generator = HashMapGenerator<K::Generator, V::Generator, K, V>;
222    fn default_generator() -> Self::Generator {
223        hashmaps(K::default_generator(), V::default_generator())
224    }
225}
226
227/// Derive a generator for a struct type defined externally.
228///
229/// This macro creates a hidden generator struct with builder methods for each field,
230/// and implements [`DefaultGenerator`] for the type
231/// so it can be used with [`default`].
232///
233/// # Example
234///
235/// ```ignore
236/// // Externally defined
237/// pub struct Person {
238///     pub name: String,
239///     pub age: u32,
240/// }
241///
242/// // In your tests:
243/// use hegel::derive_generator;
244/// use hegel::generators::{self as gs, DefaultGenerator, Generator};
245/// use production_crate::Person;
246///
247/// derive_generator!(Person {
248///     name: String,
249///     age: u32,
250/// });
251///
252/// // default now supports Person:
253/// let generator = gs::default::<Person>()
254///     .name(gs::from_regex("[A-Z][a-z]+"))
255///     .age(gs::integers::<u32>().min_value(0).max_value(120));
256///
257/// let person: Person = tc.draw(generator);
258/// ```
259#[macro_export]
260macro_rules! derive_generator {
261    ($struct_name:ident { $($field_name:ident : $field_type:ty),* $(,)? }) => {
262        const _: () = {
263            $crate::paste::paste! {
264                pub struct [<$struct_name Generator>]<'a> {
265                    $(
266                        $field_name: $crate::generators::BoxedGenerator<'a, $field_type>,
267                    )*
268                }
269
270                impl<'a> [<$struct_name Generator>]<'a> {
271                    pub fn new() -> Self
272                    where
273                        $($field_type: $crate::generators::DefaultGenerator,)*
274                        $(<$field_type as $crate::generators::DefaultGenerator>::Generator: Send + Sync + 'a,)*
275                    {
276                        use $crate::generators::{DefaultGenerator, Generator};
277                        Self {
278                            $($field_name: <$field_type as DefaultGenerator>::default_generator().boxed(),)*
279                        }
280                    }
281
282                    $(
283                        pub fn $field_name<G>(mut self, generator: G) -> Self
284                        where
285                            G: $crate::generators::Generator<$field_type> + Send + Sync + 'a,
286                        {
287                            use $crate::generators::Generator;
288                            self.$field_name = generator.boxed();
289                            self
290                        }
291                    )*
292                }
293
294                impl<'a> Default for [<$struct_name Generator>]<'a>
295                where
296                    $($field_type: $crate::generators::DefaultGenerator,)*
297                    $(<$field_type as $crate::generators::DefaultGenerator>::Generator: Send + Sync + 'a,)*
298                {
299                    fn default() -> Self {
300                        Self::new()
301                    }
302                }
303
304                impl<'a> $crate::generators::Generator<$struct_name> for [<$struct_name Generator>]<'a> {
305                    fn do_draw(&self, __tc: &$crate::TestCase) -> $struct_name {
306                        use $crate::generators::Generator;
307                        $struct_name {
308                            $($field_name: self.$field_name.do_draw(__tc),)*
309                        }
310                    }
311                }
312
313                impl $crate::generators::DefaultGenerator for $struct_name
314                where
315                    $($field_type: $crate::generators::DefaultGenerator,)*
316                    $(<$field_type as $crate::generators::DefaultGenerator>::Generator: Send + Sync + 'static,)*
317                {
318                    type Generator = [<$struct_name Generator>]<'static>;
319                    fn default_generator() -> Self::Generator {
320                        [<$struct_name Generator>]::new()
321                    }
322                }
323            }
324        };
325    };
326}