bolero_engine/
test.rs

1use crate::{
2    driver, input::SliceDebug, panic, panic::PanicError, Failure, Input, IntoResult, Seed,
3    ValueGenerator,
4};
5use std::panic::RefUnwindSafe;
6
7/// Trait for defining a test case
8pub trait Test: Sized {
9    /// The input value for the test case
10    type Value;
11
12    /// Execute one test with the given input
13    fn test<T: Input<Result<bool, PanicError>>>(
14        &mut self,
15        input: &mut T,
16    ) -> Result<bool, PanicError>;
17
18    /// Generate a value for the given input.
19    ///
20    /// Note: this is used for printing the value related to a test failure
21    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value;
22
23    /// Shrink the input to a simpler form
24    fn shrink<I: crate::shrink::Input>(
25        &mut self,
26        input: I,
27        seed: Option<Seed>,
28        options: &driver::Options,
29    ) -> Option<Failure<Self::Value>> {
30        crate::shrink::shrink(self, input, seed, options)
31    }
32}
33
34impl<F: RefUnwindSafe + FnMut(&[u8]) -> Ret, Ret> Test for F
35where
36    Ret: IntoResult,
37{
38    type Value = SliceDebug<Vec<u8>>;
39
40    #[inline]
41    fn test<T: Input<Result<bool, PanicError>>>(
42        &mut self,
43        input: &mut T,
44    ) -> Result<bool, PanicError> {
45        input.with_slice(&mut |slice| {
46            panic::catch(|| {
47                let res = (self)(slice);
48                match res.into_result() {
49                    Ok(()) => Ok(true),
50                    Err(err) => Err(err),
51                }
52            })
53        })
54    }
55
56    #[inline]
57    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value {
58        input.with_slice(&mut |slice| SliceDebug(slice.to_vec()))
59    }
60}
61
62pub struct BorrowedSliceTest<F> {
63    fun: F,
64}
65
66impl<F> BorrowedSliceTest<F> {
67    pub fn new(fun: F) -> Self {
68        Self { fun }
69    }
70}
71
72impl<F: RefUnwindSafe + FnMut(&[u8]) -> Ret, Ret> Test for BorrowedSliceTest<F>
73where
74    Ret: IntoResult,
75{
76    type Value = SliceDebug<Vec<u8>>;
77
78    #[inline]
79    fn test<T: Input<Result<bool, PanicError>>>(
80        &mut self,
81        input: &mut T,
82    ) -> Result<bool, PanicError> {
83        input.with_slice(&mut |slice| {
84            panic::catch(|| {
85                let res = (self.fun)(slice);
86                match res.into_result() {
87                    Ok(()) => Ok(true),
88                    Err(err) => Err(err),
89                }
90            })
91        })
92    }
93
94    #[inline]
95    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value {
96        input.with_slice(&mut |slice| SliceDebug(slice.to_vec()))
97    }
98}
99
100pub struct ClonedSliceTest<F> {
101    fun: F,
102}
103
104impl<F> ClonedSliceTest<F> {
105    pub fn new(fun: F) -> Self {
106        Self { fun }
107    }
108}
109
110impl<F: RefUnwindSafe + FnMut(Vec<u8>) -> Ret, Ret> Test for ClonedSliceTest<F>
111where
112    Ret: IntoResult,
113{
114    type Value = SliceDebug<Vec<u8>>;
115
116    #[inline]
117    fn test<T: Input<Result<bool, PanicError>>>(
118        &mut self,
119        input: &mut T,
120    ) -> Result<bool, PanicError> {
121        input.with_slice(&mut |slice| {
122            panic::catch(|| {
123                let input = slice.to_vec();
124                let res = (self.fun)(input);
125                match res.into_result() {
126                    Ok(()) => Ok(true),
127                    Err(err) => Err(err),
128                }
129            })
130        })
131    }
132
133    #[inline]
134    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value {
135        input.with_slice(&mut |slice| SliceDebug(slice.to_vec()))
136    }
137}
138
139/// Lazily generates a new value for the given driver
140#[cfg(not(kani))]
141macro_rules! generate_value {
142    ($self:ident, $driver:ident) => {{
143        let forward_panic = crate::panic::forward_panic(true);
144        let value = if let Some(value) = $self.value.as_mut() {
145            if $self.produce.mutate($driver, value).is_some() {
146                value
147            } else {
148                crate::panic::forward_panic(forward_panic);
149                return Ok(false);
150            }
151        } else if let Some(value) = $self.produce.generate($driver) {
152            $self.value = Some(value);
153            $self.value.as_ref().unwrap()
154        } else {
155            crate::panic::forward_panic(forward_panic);
156            return Ok(false);
157        };
158        crate::panic::forward_panic(forward_panic);
159        value
160    }};
161}
162#[cfg(kani)]
163macro_rules! generate_value {
164    ($self:ident, $driver:ident) => {{
165        $self.value = $self.produce.generate($driver);
166        kani::assume($self.value.is_some());
167        $self.value.as_ref().unwrap()
168    }};
169}
170
171pub struct BorrowedGeneratorTest<F, G, V> {
172    fun: F,
173    produce: G,
174    value: Option<V>,
175}
176
177impl<F, G, V> BorrowedGeneratorTest<F, G, V> {
178    pub fn new(fun: F, produce: G) -> Self {
179        Self {
180            fun,
181            produce,
182            value: None,
183        }
184    }
185}
186
187impl<F: RefUnwindSafe + FnMut(&G::Output) -> Ret, G: ValueGenerator, Ret> Test
188    for BorrowedGeneratorTest<F, G, G::Output>
189where
190    Ret: IntoResult,
191    G::Output: core::fmt::Debug,
192{
193    type Value = G::Output;
194
195    #[inline]
196    fn test<T: Input<Result<bool, PanicError>>>(
197        &mut self,
198        input: &mut T,
199    ) -> Result<bool, PanicError> {
200        input.with_driver(&mut |driver| {
201            let fun = &mut self.fun;
202
203            // The value will not be reused after being captured, so it is unwind safe
204            let value = core::panic::AssertUnwindSafe(generate_value!(self, driver));
205
206            panic::catch(|| {
207                let res = (fun)(&value);
208                match res.into_result() {
209                    Ok(()) => Ok(true),
210                    Err(err) => Err(err),
211                }
212            })
213        })
214    }
215
216    #[inline]
217    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value {
218        input.with_driver(&mut |driver| {
219            let forward_panic = crate::panic::forward_panic(true);
220            let value = self.produce.generate(driver).unwrap();
221            crate::panic::forward_panic(forward_panic);
222            value
223        })
224    }
225}
226
227pub struct ClonedGeneratorTest<F, G, V> {
228    fun: F,
229    produce: G,
230    value: Option<V>,
231}
232
233impl<F, G, V> ClonedGeneratorTest<F, G, V> {
234    pub fn new(fun: F, produce: G) -> Self {
235        Self {
236            fun,
237            produce,
238            value: None,
239        }
240    }
241}
242
243impl<F: RefUnwindSafe + FnMut(G::Output) -> Ret, G: ValueGenerator, Ret> Test
244    for ClonedGeneratorTest<F, G, G::Output>
245where
246    Ret: IntoResult,
247    G::Output: core::fmt::Debug + Clone + RefUnwindSafe,
248{
249    type Value = G::Output;
250
251    #[inline]
252    fn test<T: Input<Result<bool, PanicError>>>(
253        &mut self,
254        input: &mut T,
255    ) -> Result<bool, PanicError> {
256        input.with_driver(&mut |driver| {
257            let fun = &mut self.fun;
258
259            let value = generate_value!(self, driver);
260
261            #[cfg(kani)]
262            let input = {
263                let _ = value;
264                self.value.take().unwrap()
265            };
266
267            #[cfg(not(kani))]
268            let input = value.clone();
269
270            // The value will not be reused after being captured, so it is unwind safe
271            let input = core::panic::AssertUnwindSafe(input);
272
273            panic::catch(move || {
274                let core::panic::AssertUnwindSafe(input) = input;
275                let res = (fun)(input);
276                match res.into_result() {
277                    Ok(()) => Ok(true),
278                    Err(err) => Err(err),
279                }
280            })
281        })
282    }
283
284    #[inline]
285    fn generate_value<T: Input<Self::Value>>(&self, input: &mut T) -> Self::Value {
286        input.with_driver(&mut |driver| {
287            let forward_panic = crate::panic::forward_panic(true);
288            let value = self.produce.generate(driver).unwrap();
289            crate::panic::forward_panic(forward_panic);
290            value
291        })
292    }
293}