Skip to main content

hegel/generators/
default.rs

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