Skip to main content

quickcheck/
tester.rs

1use std::cmp;
2use std::env;
3use std::fmt::Debug;
4use std::panic;
5
6use crate::{
7    tester::Status::{Discard, Fail, Pass},
8    Arbitrary, Gen,
9};
10
11/// The main `QuickCheck` type for setting configuration and running
12/// `QuickCheck`.
13pub struct QuickCheck {
14    tests: u64,
15    max_tests: u64,
16    min_tests_passed: u64,
17    rng: Gen,
18}
19
20fn qc_tests() -> u64 {
21    let default = 100;
22    match env::var("QUICKCHECK_TESTS") {
23        Ok(val) => val.parse().unwrap_or(default),
24        Err(_) => default,
25    }
26}
27
28fn qc_max_tests() -> u64 {
29    let default = 10_000;
30    match env::var("QUICKCHECK_MAX_TESTS") {
31        Ok(val) => val.parse().unwrap_or(default),
32        Err(_) => default,
33    }
34}
35
36fn qc_gen_size() -> usize {
37    let default = 100;
38    match env::var("QUICKCHECK_GENERATOR_SIZE") {
39        Ok(val) => val.parse().unwrap_or(default),
40        Err(_) => default,
41    }
42}
43
44fn qc_min_tests_passed() -> u64 {
45    let default = 0;
46    match env::var("QUICKCHECK_MIN_TESTS_PASSED") {
47        Ok(val) => val.parse().unwrap_or(default),
48        Err(_) => default,
49    }
50}
51
52impl Default for QuickCheck {
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58impl QuickCheck {
59    /// Creates a new `QuickCheck` value.
60    ///
61    /// This can be used to run `QuickCheck` on things that implement
62    /// `Testable`. You may also adjust the configuration, such as the
63    /// number of tests to run.
64    ///
65    /// By default, the maximum number of passed tests is set to `100`, the max
66    /// number of overall tests is set to `10000` and the generator is created
67    /// with a size of `100`.
68    pub fn new() -> QuickCheck {
69        let rng = Gen::new(qc_gen_size());
70        let tests = qc_tests();
71        let max_tests = cmp::max(tests, qc_max_tests());
72        let min_tests_passed = qc_min_tests_passed();
73
74        QuickCheck { tests, max_tests, min_tests_passed, rng }
75    }
76
77    /// Set the random number generator to be used by `QuickCheck`.
78    pub fn rng(self, rng: Gen) -> QuickCheck {
79        QuickCheck { rng, ..self }
80    }
81
82    /// Set the random number generator to be used by `QuickCheck`.
83    ///
84    /// This is **DEPRECATED**. Using this method on Rust 2024 or newer
85    /// requires the raw identifier syntax because `gen` is now a keyword.
86    /// Instead, prefer the [`QuickCheck::rng`] method.
87    #[deprecated(since = "1.1.0", note = "use `set_rng` instead")]
88    pub fn r#gen(self, rng: Gen) -> QuickCheck {
89        self.rng(rng)
90    }
91
92    /// Set the number of tests to run.
93    ///
94    /// This actually refers to the maximum number of *passed* tests that
95    /// can occur. Namely, if a test causes a failure, future testing on that
96    /// property stops. Additionally, if tests are discarded, there may be
97    /// fewer than `tests` passed.
98    pub fn tests(mut self, tests: u64) -> QuickCheck {
99        self.tests = tests;
100        self
101    }
102
103    /// Set the maximum number of tests to run.
104    ///
105    /// The number of invocations of a property will never exceed this number.
106    /// This is necessary to cap the number of tests because `QuickCheck`
107    /// properties can discard tests.
108    pub fn max_tests(mut self, max_tests: u64) -> QuickCheck {
109        self.max_tests = max_tests;
110        self
111    }
112
113    /// Set the minimum number of tests that needs to pass.
114    ///
115    /// This actually refers to the minimum number of *valid* *passed* tests
116    /// that needs to pass for the property to be considered successful.
117    pub fn min_tests_passed(mut self, min_tests_passed: u64) -> QuickCheck {
118        self.min_tests_passed = min_tests_passed;
119        self
120    }
121
122    /// Tests a property and returns the result.
123    ///
124    /// The result returned is either the number of tests passed or a witness
125    /// of failure.
126    ///
127    /// (If you're using Rust's unit testing infrastructure, then you'll
128    /// want to use the `quickcheck` method, which will `panic!` on failure.)
129    pub fn quicktest<A>(&mut self, f: A) -> Result<u64, TestResult>
130    where
131        A: Testable,
132    {
133        let mut n_tests_passed = 0;
134        for _ in 0..self.max_tests {
135            if n_tests_passed >= self.tests {
136                break;
137            }
138            match f.result(&mut self.rng) {
139                TestResult { status: Pass, .. } => n_tests_passed += 1,
140                TestResult { status: Discard, .. } => continue,
141                r @ TestResult { status: Fail, .. } => return Err(r),
142            }
143        }
144        Ok(n_tests_passed)
145    }
146
147    /// Tests a property and calls `panic!` on failure.
148    ///
149    /// The `panic!` message will include a (hopefully) minimal witness of
150    /// failure.
151    ///
152    /// It is appropriate to use this method with Rust's unit testing
153    /// infrastructure.
154    ///
155    /// Note that if the environment variable `RUST_LOG` is set to enable
156    /// `info` level log messages for the `quickcheck` crate, then this will
157    /// include output on how many `QuickCheck` tests were passed.
158    ///
159    /// # Example
160    ///
161    /// ```rust
162    /// use quickcheck::QuickCheck;
163    ///
164    /// fn prop_reverse_reverse() {
165    ///     fn revrev(xs: Vec<usize>) -> bool {
166    ///         let rev: Vec<_> = xs.clone().into_iter().rev().collect();
167    ///         let revrev: Vec<_> = rev.into_iter().rev().collect();
168    ///         xs == revrev
169    ///     }
170    ///     QuickCheck::new().quickcheck(revrev as fn(Vec<usize>) -> bool);
171    /// }
172    /// ```
173    pub fn quickcheck<A>(&mut self, f: A)
174    where
175        A: Testable,
176    {
177        // Ignore log init failures, implying it has already been done.
178        let _ = crate::env_logger_init();
179
180        let n_tests_passed = match self.quicktest(f) {
181            Ok(n_tests_passed) => n_tests_passed,
182            Err(result) => { ::core::panicking::panic_display(&result.failed_msg()); }panic!("{}", result.failed_msg()),
183        };
184
185        if n_tests_passed >= self.min_tests_passed {
186            {
    {
        let lvl = ::log::Level::Info;
        if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
            ::log::__private_api::log({ ::log::__private_api::GlobalLogger },
                format_args!("(Passed {0} QuickCheck tests.)",
                    n_tests_passed), lvl,
                &("quickcheck::tester", "quickcheck::tester",
                        ::log::__private_api::loc()), ());
        }
    }
};info!("(Passed {} QuickCheck tests.)", n_tests_passed);
187        } else {
188            {
    ::core::panicking::panic_fmt(format_args!("(Unable to generate enough tests, {0} not discarded.)",
            n_tests_passed));
};panic!(
189                "(Unable to generate enough tests, {} not discarded.)",
190                n_tests_passed
191            );
192        }
193    }
194}
195
196/// Convenience function for running `QuickCheck`.
197///
198/// This is an alias for `QuickCheck::new().quickcheck(f)`.
199pub fn quickcheck<A: Testable>(f: A) {
200    QuickCheck::new().quickcheck(f)
201}
202
203/// Describes the status of a single instance of a test.
204///
205/// All testable things must be capable of producing a `TestResult`.
206#[derive(#[automatically_derived]
impl ::core::clone::Clone for TestResult {
    #[inline]
    fn clone(&self) -> TestResult {
        TestResult {
            status: ::core::clone::Clone::clone(&self.status),
            arguments: ::core::clone::Clone::clone(&self.arguments),
            err: ::core::clone::Clone::clone(&self.err),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for TestResult {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "TestResult",
            "status", &self.status, "arguments", &self.arguments, "err",
            &&self.err)
    }
}Debug)]
207pub struct TestResult {
208    status: Status,
209    arguments: Option<Vec<String>>,
210    err: Option<String>,
211}
212
213/// Whether a test has passed, failed or been discarded.
214#[derive(#[automatically_derived]
impl ::core::clone::Clone for Status {
    #[inline]
    fn clone(&self) -> Status {
        match self {
            Status::Pass => Status::Pass,
            Status::Fail => Status::Fail,
            Status::Discard => Status::Discard,
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Status {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                Status::Pass => "Pass",
                Status::Fail => "Fail",
                Status::Discard => "Discard",
            })
    }
}Debug)]
215enum Status {
216    Pass,
217    Fail,
218    Discard,
219}
220
221impl TestResult {
222    /// Produces a test result that indicates the current test has passed.
223    pub fn passed() -> TestResult {
224        TestResult::from_bool(true)
225    }
226
227    /// Produces a test result that indicates the current test has failed.
228    pub fn failed() -> TestResult {
229        TestResult::from_bool(false)
230    }
231
232    /// Produces a test result that indicates failure from a runtime error.
233    pub fn error<S: Into<String>>(msg: S) -> TestResult {
234        let mut r = TestResult::from_bool(false);
235        r.err = Some(msg.into());
236        r
237    }
238
239    /// Produces a test result that instructs `quickcheck` to ignore it.
240    /// This is useful for restricting the domain of your properties.
241    /// When a test is discarded, `quickcheck` will replace it with a
242    /// fresh one (up to a certain limit).
243    pub fn discard() -> TestResult {
244        TestResult { status: Discard, arguments: None, err: None }
245    }
246
247    /// Converts a `bool` to a `TestResult`. A `true` value indicates that
248    /// the test has passed and a `false` value indicates that the test
249    /// has failed.
250    pub fn from_bool(b: bool) -> TestResult {
251        TestResult {
252            status: if b { Pass } else { Fail },
253            arguments: None,
254            err: None,
255        }
256    }
257
258    /// Tests if a "procedure" fails when executed. The test passes only if
259    /// `f` generates a task failure during its execution.
260    pub fn must_fail<T, F>(f: F) -> TestResult
261    where
262        F: FnOnce() -> T,
263        F: 'static,
264        T: 'static,
265    {
266        let f = panic::AssertUnwindSafe(f);
267        TestResult::from_bool(panic::catch_unwind(f).is_err())
268    }
269
270    /// Returns `true` if and only if this test result describes a failing
271    /// test.
272    pub fn is_failure(&self) -> bool {
273        match self.status {
274            Fail => true,
275            Pass | Discard => false,
276        }
277    }
278
279    /// Returns `true` if and only if this test result describes a failing
280    /// test as a result of a run time error.
281    pub fn is_error(&self) -> bool {
282        self.is_failure() && self.err.is_some()
283    }
284
285    fn failed_msg(&self) -> String {
286        let arguments_msg = match self.arguments {
287            None => "No Arguments Provided".to_owned(),
288            Some(ref args) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Arguments: ({0})",
                args.join(", ")))
    })format!("Arguments: ({})", args.join(", ")),
289        };
290        match self.err {
291            None => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("[quickcheck] TEST FAILED. {0}",
                arguments_msg))
    })format!("[quickcheck] TEST FAILED. {arguments_msg}"),
292            Some(ref err) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("[quickcheck] TEST FAILED (runtime error). {0}\nError: {1}",
                arguments_msg, err))
    })format!(
293                "[quickcheck] TEST FAILED (runtime error). {arguments_msg}\nError: {err}"
294            ),
295        }
296    }
297}
298
299/// A shorter way of producing a `TestResult` from a `bool`.
300///
301/// # Example
302///
303/// ```rust
304/// use quickcheck::TestResult;
305///
306/// let result: TestResult = (2 > 1).into();
307/// assert!(!result.is_failure());
308/// ```
309impl From<bool> for TestResult {
310    fn from(b: bool) -> TestResult {
311        TestResult::from_bool(b)
312    }
313}
314
315/// `Testable` describes types (e.g., a function) whose values can be
316/// tested.
317///
318/// Anything that can be tested must be capable of producing a `TestResult`
319/// given a random number generator. This is trivial for types like `bool`,
320/// which are just converted to either a passing or failing test result.
321///
322/// For functions, an implementation must generate random arguments
323/// and potentially shrink those arguments if they produce a failure.
324///
325/// It's unlikely that you'll have to implement this trait yourself.
326pub trait Testable: 'static {
327    fn result(&self, _: &mut Gen) -> TestResult;
328}
329
330impl Testable for bool {
331    fn result(&self, _: &mut Gen) -> TestResult {
332        TestResult::from_bool(*self)
333    }
334}
335
336impl Testable for () {
337    fn result(&self, _: &mut Gen) -> TestResult {
338        TestResult::passed()
339    }
340}
341
342impl Testable for TestResult {
343    fn result(&self, _: &mut Gen) -> TestResult {
344        self.clone()
345    }
346}
347
348impl<A, E> Testable for Result<A, E>
349where
350    A: Testable,
351    E: Debug + 'static,
352{
353    fn result(&self, g: &mut Gen) -> TestResult {
354        match *self {
355            Ok(ref r) => r.result(g),
356            Err(ref err) => TestResult::error(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", err))
    })format!("{err:?}")),
357        }
358    }
359}
360
361/// Return a vector of the debug formatting of each item in `args`
362fn debug_reprs(args: &[&dyn Debug]) -> Vec<String> {
363    args.iter().map(|x| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", x))
    })format!("{x:?}")).collect()
364}
365
366macro_rules! testable_fn {
367    ($($name: ident),*) => {
368
369impl<T: Testable,
370     $($name: Arbitrary + Debug),*> Testable for fn($($name),*) -> T {
371    #[allow(non_snake_case)]
372    fn result(&self, g: &mut Gen) -> TestResult {
373        let self_ = *self;
374        let a: ($($name,)*) = Arbitrary::arbitrary(g);
375        let ( $($name,)* ) = a.clone();
376        let mut r = safe(move || {self_($($name),*)}).result(g);
377
378        if r.is_failure() {
379            let mut a = a.shrink();
380            while let Some(t) = a.next() {
381                let ($($name,)*) = t.clone();
382                let mut r_new = safe(move || {self_($($name),*)}).result(g);
383                if r_new.is_failure() {
384                    {
385                        let ($(ref $name,)*) : ($($name,)*) = t;
386                        r_new.arguments = Some(debug_reprs(&[$($name),*]));
387                    }
388
389                    // The shrunk value *does* witness a failure, so remember
390                    // it for now
391                    r = r_new;
392
393                    // ... and switch over to that value, i.e. try to shrink
394                    // it further.
395                    a = t.shrink()
396                }
397            }
398        }
399
400        r
401    }
402}}}
403
404impl<T: Testable> Testable for fn() -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: () = Arbitrary::arbitrary(g);
        let () = a.clone();
        let mut r = safe(move || { self_() }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let () = t.clone();
                let mut r_new = safe(move || { self_() }).result(g);
                if r_new.is_failure() {
                    {
                        let (): () = t;
                        r_new.arguments = Some(debug_reprs(&[]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!();
405impl<T: Testable, A: Arbitrary + Debug> Testable for fn(A) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A,) = Arbitrary::arbitrary(g);
        let (A,) = a.clone();
        let mut r = safe(move || { self_(A) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A,) = t.clone();
                let mut r_new = safe(move || { self_(A) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A,): (A,) = t;
                        r_new.arguments = Some(debug_reprs(&[A]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A);
406impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug> Testable for
    fn(A, B) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B) = Arbitrary::arbitrary(g);
        let (A, B) = a.clone();
        let mut r = safe(move || { self_(A, B) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B) = t.clone();
                let mut r_new = safe(move || { self_(A, B) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B): (A, B) = t;
                        r_new.arguments = Some(debug_reprs(&[A, B]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B);
407impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug> Testable for fn(A, B, C) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C) = Arbitrary::arbitrary(g);
        let (A, B, C) = a.clone();
        let mut r = safe(move || { self_(A, B, C) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C) = t.clone();
                let mut r_new = safe(move || { self_(A, B, C) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C): (A, B, C) = t;
                        r_new.arguments = Some(debug_reprs(&[A, B, C]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C);
408impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug, D: Arbitrary + Debug> Testable for fn(A, B, C, D) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C, D) = Arbitrary::arbitrary(g);
        let (A, B, C, D) = a.clone();
        let mut r = safe(move || { self_(A, B, C, D) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C, D) = t.clone();
                let mut r_new = safe(move || { self_(A, B, C, D) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C, ref D): (A, B, C, D) = t;
                        r_new.arguments = Some(debug_reprs(&[A, B, C, D]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C, D);
409impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug, D: Arbitrary + Debug, E: Arbitrary + Debug> Testable for
    fn(A, B, C, D, E) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C, D, E) = Arbitrary::arbitrary(g);
        let (A, B, C, D, E) = a.clone();
        let mut r = safe(move || { self_(A, B, C, D, E) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C, D, E) = t.clone();
                let mut r_new =
                    safe(move || { self_(A, B, C, D, E) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C, ref D, ref E): (A, B, C, D, E) =
                            t;
                        r_new.arguments = Some(debug_reprs(&[A, B, C, D, E]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C, D, E);
410impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug, D: Arbitrary + Debug, E: Arbitrary + Debug, F: Arbitrary + Debug>
    Testable for fn(A, B, C, D, E, F) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C, D, E, F) = Arbitrary::arbitrary(g);
        let (A, B, C, D, E, F) = a.clone();
        let mut r = safe(move || { self_(A, B, C, D, E, F) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C, D, E, F) = t.clone();
                let mut r_new =
                    safe(move || { self_(A, B, C, D, E, F) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C, ref D, ref E, ref F):
                                (A, B, C, D, E, F) = t;
                        r_new.arguments = Some(debug_reprs(&[A, B, C, D, E, F]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C, D, E, F);
411impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug, D: Arbitrary + Debug, E: Arbitrary + Debug, F: Arbitrary + Debug,
    G: Arbitrary + Debug> Testable for fn(A, B, C, D, E, F, G) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C, D, E, F, G) = Arbitrary::arbitrary(g);
        let (A, B, C, D, E, F, G) = a.clone();
        let mut r = safe(move || { self_(A, B, C, D, E, F, G) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C, D, E, F, G) = t.clone();
                let mut r_new =
                    safe(move || { self_(A, B, C, D, E, F, G) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C, ref D, ref E, ref F, ref G):
                                (A, B, C, D, E, F, G) = t;
                        r_new.arguments = Some(debug_reprs(&[A, B, C, D, E, F, G]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C, D, E, F, G);
412impl<T: Testable, A: Arbitrary + Debug, B: Arbitrary + Debug, C: Arbitrary +
    Debug, D: Arbitrary + Debug, E: Arbitrary + Debug, F: Arbitrary + Debug,
    G: Arbitrary + Debug, H: Arbitrary + Debug> Testable for
    fn(A, B, C, D, E, F, G, H) -> T {
    #[allow(non_snake_case)]
    fn result(&self, g: &mut Gen) -> TestResult {
        let self_ = *self;
        let a: (A, B, C, D, E, F, G, H) = Arbitrary::arbitrary(g);
        let (A, B, C, D, E, F, G, H) = a.clone();
        let mut r = safe(move || { self_(A, B, C, D, E, F, G, H) }).result(g);
        if r.is_failure() {
            let mut a = a.shrink();
            while let Some(t) = a.next() {
                let (A, B, C, D, E, F, G, H) = t.clone();
                let mut r_new =
                    safe(move || { self_(A, B, C, D, E, F, G, H) }).result(g);
                if r_new.is_failure() {
                    {
                        let (ref A, ref B, ref C, ref D, ref E, ref F, ref G,
                                ref H): (A, B, C, D, E, F, G, H) = t;
                        r_new.arguments =
                            Some(debug_reprs(&[A, B, C, D, E, F, G, H]));
                    }
                    r = r_new;
                    a = t.shrink()
                }
            }
        }
        r
    }
}testable_fn!(A, B, C, D, E, F, G, H);
413
414fn safe<T, F>(fun: F) -> Result<T, String>
415where
416    F: FnOnce() -> T,
417    F: 'static,
418    T: 'static,
419{
420    panic::catch_unwind(panic::AssertUnwindSafe(fun)).map_err(|any_err| {
421        // Extract common types of panic payload:
422        // panic and assert produce &str or String
423        if let Some(&s) = any_err.downcast_ref::<&str>() {
424            s.to_owned()
425        } else if let Some(s) = any_err.downcast_ref::<String>() {
426            s.to_owned()
427        } else {
428            "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
429        }
430    })
431}
432
433#[cfg(test)]
434mod test {
435    use crate::{Gen, QuickCheck};
436
437    #[test]
438    fn shrinking_regression_issue_126() {
439        fn thetest(vals: Vec<bool>) -> bool {
440            vals.iter().filter(|&v| *v).count() < 2
441        }
442        let failing_case = QuickCheck::new()
443            .quicktest(thetest as fn(vals: Vec<bool>) -> bool)
444            .unwrap_err();
445        let expected_argument = format!("{:?}", [true, true]);
446        assert_eq!(failing_case.arguments, Some(vec![expected_argument]));
447    }
448
449    #[test]
450    fn size_for_small_types_issue_143() {
451        fn t(_: i8) -> bool {
452            true
453        }
454        QuickCheck::new().rng(Gen::new(129)).quickcheck(t as fn(i8) -> bool);
455    }
456
457    #[test]
458    fn regression_signed_shrinker_panic() {
459        fn foo_can_shrink(v: i8) -> bool {
460            let _ = crate::Arbitrary::shrink(&v).take(100).count();
461            true
462        }
463        crate::quickcheck(foo_can_shrink as fn(i8) -> bool);
464    }
465}