| //- |
| // Copyright 2017, 2019 The proptest developers |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| use crate::std_facade::fmt; |
| |
| /// Easily define `proptest` tests. |
| /// |
| /// Within `proptest!`, define one or more functions without return type |
| /// normally, except instead of putting `: type` after each parameter, write |
| /// `in strategy`, where `strategy` is an expression evaluating to some |
| /// `Strategy`. |
| /// |
| /// Each function will be wrapped in a function which sets up a `TestRunner`, |
| /// and then invokes the function body with inputs generated according to the |
| /// strategies. |
| /// |
| /// ### Example |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn test_addition(a in 0..10, b in 0..10) { |
| /// prop_assert!(a + b <= 18); |
| /// } |
| /// |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn test_string_concat(a in ".*", b in ".*") { |
| /// let cat = format!("{}{}", a, b); |
| /// prop_assert_eq!(a.len() + b.len(), cat.len()); |
| /// } |
| /// } |
| /// # |
| /// # fn main() { test_addition(); test_string_concat(); } |
| /// ``` |
| /// |
| /// You can also use the normal argument syntax `pattern: type` as in: |
| /// |
| /// ```rust |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn addition_is_commutative(a: u8, b: u8) { |
| /// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); |
| /// } |
| /// |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn test_string_concat(a in ".*", b: String) { |
| /// let cat = format!("{}{}", a, b); |
| /// prop_assert_eq!(a.len() + b.len(), cat.len()); |
| /// } |
| /// } |
| /// # |
| /// # fn main() { addition_is_commutative(); test_string_concat(); } |
| /// ``` |
| /// |
| /// As you can see, you can mix `pattern: type` and `pattern in expr`. |
| /// Due to limitations in `macro_rules!`, `pattern: type` does not work in |
| /// all circumstances. In such a case, use `(pattern): type` instead. |
| /// |
| /// To override the default configuration, you can start the `proptest!` block |
| /// with `#![proptest_config(expr)]`, where `expr` is an expression that |
| /// evaluates to a `proptest::test_runner::Config` (or a reference to one). |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// #![proptest_config(ProptestConfig { |
| /// cases: 99, .. ProptestConfig::default() |
| /// })] |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn test_addition(a in 0..10, b in 0..10) { |
| /// prop_assert!(a + b <= 18); |
| /// } |
| /// } |
| /// # |
| /// # fn main() { test_addition(); } |
| /// ``` |
| /// |
| /// ## Closure-Style Invocation |
| /// |
| /// As of proptest 0.8.1, an alternative, "closure-style" invocation is |
| /// supported. In this form, `proptest!` is a function-like macro taking a |
| /// closure-esque argument. This makes it possible to run multiple tests that |
| /// require some expensive setup process. Note that the "fork" and "timeout" |
| /// features are _not_ supported in closure style. |
| /// |
| /// To use a custom configuration, pass the `Config` object as a first |
| /// argument. |
| /// |
| /// ### Example |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// #[derive(Debug)] |
| /// struct BigStruct { /* Lots of fields ... */ } |
| /// |
| /// fn very_expensive_function() -> BigStruct { |
| /// // Lots of code... |
| /// BigStruct { /* fields */ } |
| /// } |
| /// |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn my_test() { |
| /// // We create just one `BigStruct` |
| /// let big_struct = very_expensive_function(); |
| /// |
| /// // But now can run multiple tests without needing to build it every time. |
| /// // Note the extra parentheses around the arguments are currently |
| /// // required. |
| /// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { |
| /// // Test stuff |
| /// }); |
| /// |
| /// // `move` closures are also supported |
| /// proptest!(move |(x in 0u32..42u32)| { |
| /// // Test other stuff |
| /// }); |
| /// |
| /// // You can pass a custom configuration as the first argument |
| /// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { |
| /// // Test more stuff |
| /// }); |
| /// } |
| /// # |
| /// # fn main() { my_test(); } |
| /// ``` |
| #[macro_export] |
| macro_rules! proptest { |
| (#![proptest_config($config:expr)] |
| $( |
| $(#[$meta:meta])* |
| fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block |
| )*) => { |
| $( |
| $(#[$meta])* |
| fn $test_name() { |
| let mut config = $config.clone(); |
| config.test_name = Some( |
| concat!(module_path!(), "::", stringify!($test_name))); |
| $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); |
| } |
| )* |
| }; |
| (#![proptest_config($config:expr)] |
| $( |
| $(#[$meta:meta])* |
| fn $test_name:ident($($arg:tt)+) $body:block |
| )*) => { |
| $( |
| $(#[$meta])* |
| fn $test_name() { |
| let mut config = $config.clone(); |
| config.test_name = Some( |
| concat!(module_path!(), "::", stringify!($test_name))); |
| $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); |
| } |
| )* |
| }; |
| |
| ($( |
| $(#[$meta:meta])* |
| fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block |
| )*) => { $crate::proptest! { |
| #![proptest_config($crate::test_runner::Config::default())] |
| $($(#[$meta])* |
| fn $test_name($($parm in $strategy),+) $body)* |
| } }; |
| |
| ($( |
| $(#[$meta:meta])* |
| fn $test_name:ident($($arg:tt)+) $body:block |
| )*) => { $crate::proptest! { |
| #![proptest_config($crate::test_runner::Config::default())] |
| $($(#[$meta])* |
| fn $test_name($($arg)+) $body)* |
| } }; |
| |
| (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { |
| $crate::proptest!( |
| $crate::test_runner::Config::default(), |
| |($($parm in $strategy),+)| $body) |
| }; |
| |
| (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { |
| $crate::proptest!( |
| $crate::test_runner::Config::default(), |
| move |($($parm in $strategy),+)| $body) |
| }; |
| |
| (|($($arg:tt)+)| $body:expr) => { |
| $crate::proptest!( |
| $crate::test_runner::Config::default(), |
| |($($arg)+)| $body) |
| }; |
| |
| (move |($($arg:tt)+)| $body:expr) => { |
| $crate::proptest!( |
| $crate::test_runner::Config::default(), |
| move |($($arg)+)| $body) |
| }; |
| |
| ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { |
| let mut config = $config.__sugar_to_owned(); |
| $crate::sugar::force_no_fork(&mut config); |
| $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) |
| } }; |
| |
| ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { |
| let mut config = $config.__sugar_to_owned(); |
| $crate::sugar::force_no_fork(&mut config); |
| $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) |
| } }; |
| |
| ($config:expr, |($($arg:tt)+)| $body:expr) => { { |
| let mut config = $config.__sugar_to_owned(); |
| $crate::sugar::force_no_fork(&mut config); |
| $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); |
| } }; |
| |
| ($config:expr, move |($($arg:tt)+)| $body:expr) => { { |
| let mut config = $config.__sugar_to_owned(); |
| $crate::sugar::force_no_fork(&mut config); |
| $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); |
| } }; |
| } |
| |
| /// Rejects the test input if assumptions are not met. |
| /// |
| /// Used directly within a function defined with `proptest!` or in any function |
| /// returning `Result<_, TestCaseError>`. |
| /// |
| /// This is invoked as `prop_assume!(condition, format, args...)`. `condition` |
| /// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The |
| /// message includes the point of invocation and the format message. `format` |
| /// and `args` may be omitted to simply use the condition itself as the |
| /// message. |
| #[macro_export] |
| macro_rules! prop_assume { |
| ($expr:expr) => { |
| $crate::prop_assume!($expr, "{}", stringify!($expr)) |
| }; |
| |
| ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { |
| if !$expr { |
| return ::core::result::Result::Err( |
| $crate::test_runner::TestCaseError::reject( |
| format!(concat!("{}:{}:{}: ", $fmt), |
| file!(), line!(), column!() |
| $(, $fmt_arg)*))); |
| } |
| }; |
| } |
| |
| /// Produce a strategy which picks one of the listed choices. |
| /// |
| /// This is conceptually equivalent to calling `prop_union` on the first two |
| /// elements and then chaining `.or()` onto the rest after implicitly boxing |
| /// all of them. As with `Union`, values shrink across elements on the |
| /// assumption that earlier ones are "simpler", so they should be listed in |
| /// order of ascending complexity when possible. |
| /// |
| /// The macro invocation has two forms. The first is to simply list the |
| /// strategies separated by commas; this will cause value generation to pick |
| /// from the strategies uniformly. The other form is to provide a weight in the |
| /// form of a `u32` before each strategy, separated from the strategy with |
| /// `=>`. |
| /// |
| /// Note that the exact type returned by the macro varies depending on how many |
| /// inputs there are. In particular, if given exactly one option, it will |
| /// return it unmodified. It is not recommended to depend on the particular |
| /// type produced by this macro. |
| /// |
| /// ## Example |
| /// |
| /// ```rust,no_run |
| /// use proptest::prelude::*; |
| /// |
| /// #[derive(Clone, Copy, Debug)] |
| /// enum MyEnum { |
| /// Big(u64), |
| /// Medium(u32), |
| /// Little(i16), |
| /// } |
| /// |
| /// # #[allow(unused_variables)] |
| /// # fn main() { |
| /// let my_enum_strategy = prop_oneof![ |
| /// prop::num::i16::ANY.prop_map(MyEnum::Little), |
| /// prop::num::u32::ANY.prop_map(MyEnum::Medium), |
| /// prop::num::u64::ANY.prop_map(MyEnum::Big), |
| /// ]; |
| /// |
| /// let my_weighted_strategy = prop_oneof![ |
| /// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), |
| /// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., |
| /// // around 50% of values will be `Medium`, and 25% for each of `Little` |
| /// // and `Big`. |
| /// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), |
| /// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), |
| /// ]; |
| /// # } |
| /// ``` |
| #[macro_export] |
| macro_rules! prop_oneof { |
| ($($item:expr),+ $(,)?) => { |
| $crate::prop_oneof![ |
| $(1 => $item),* |
| ] |
| }; |
| |
| ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr, |
| $weight5:expr => $item5:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)), |
| ($weight5, $crate::std_facade::Arc::new($item5)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr, |
| $weight5:expr => $item5:expr, |
| $weight6:expr => $item6:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)), |
| ($weight5, $crate::std_facade::Arc::new($item5)), |
| ($weight6, $crate::std_facade::Arc::new($item6)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr, |
| $weight5:expr => $item5:expr, |
| $weight6:expr => $item6:expr, |
| $weight7:expr => $item7:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)), |
| ($weight5, $crate::std_facade::Arc::new($item5)), |
| ($weight6, $crate::std_facade::Arc::new($item6)), |
| ($weight7, $crate::std_facade::Arc::new($item7)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr, |
| $weight5:expr => $item5:expr, |
| $weight6:expr => $item6:expr, |
| $weight7:expr => $item7:expr, |
| $weight8:expr => $item8:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)), |
| ($weight5, $crate::std_facade::Arc::new($item5)), |
| ($weight6, $crate::std_facade::Arc::new($item6)), |
| ($weight7, $crate::std_facade::Arc::new($item7)), |
| ($weight8, $crate::std_facade::Arc::new($item8)))) |
| }; |
| |
| ($weight0:expr => $item0:expr, |
| $weight1:expr => $item1:expr, |
| $weight2:expr => $item2:expr, |
| $weight3:expr => $item3:expr, |
| $weight4:expr => $item4:expr, |
| $weight5:expr => $item5:expr, |
| $weight6:expr => $item6:expr, |
| $weight7:expr => $item7:expr, |
| $weight8:expr => $item8:expr, |
| $weight9:expr => $item9:expr $(,)?) => { |
| $crate::strategy::TupleUnion::new( |
| (($weight0, $crate::std_facade::Arc::new($item0)), |
| ($weight1, $crate::std_facade::Arc::new($item1)), |
| ($weight2, $crate::std_facade::Arc::new($item2)), |
| ($weight3, $crate::std_facade::Arc::new($item3)), |
| ($weight4, $crate::std_facade::Arc::new($item4)), |
| ($weight5, $crate::std_facade::Arc::new($item5)), |
| ($weight6, $crate::std_facade::Arc::new($item6)), |
| ($weight7, $crate::std_facade::Arc::new($item7)), |
| ($weight8, $crate::std_facade::Arc::new($item8)), |
| ($weight9, $crate::std_facade::Arc::new($item9)))) |
| }; |
| |
| ($($weight:expr => $item:expr),+ $(,)?) => { |
| $crate::strategy::Union::new_weighted(vec![ |
| $(($weight, $crate::strategy::Strategy::boxed($item))),* |
| ]) |
| }; |
| } |
| |
| /// Convenience to define functions which produce new strategies. |
| /// |
| /// The macro has two general forms. In the first, you define a function with |
| /// two argument lists. The first argument list uses the usual syntax and |
| /// becomes exactly the argument list of the defined function. The second |
| /// argument list uses the `in strategy` syntax as with `proptest!`, and is |
| /// used to generate the other inputs for the function. The second argument |
| /// list has access to all arguments in the first. The return type indicates |
| /// the type of value being generated; the final return type of the function is |
| /// `impl Strategy<Value = $type>`. |
| /// |
| /// ```rust,no_run |
| /// # #![allow(dead_code)] |
| /// use proptest::prelude::*; |
| /// |
| /// #[derive(Clone, Debug)] |
| /// struct MyStruct { |
| /// integer: u32, |
| /// string: String, |
| /// } |
| /// |
| /// prop_compose! { |
| /// fn my_struct_strategy(max_integer: u32) |
| /// (integer in 0..max_integer, string in ".*") |
| /// -> MyStruct { |
| /// MyStruct { integer, string } |
| /// } |
| /// } |
| /// # |
| /// # fn main() { } |
| /// ``` |
| /// |
| /// This form is simply sugar around making a tuple and then calling `prop_map` |
| /// on it. You can also use `arg: type` as in `proptest! { .. }`: |
| /// |
| /// ```rust,no_run |
| /// # #![allow(dead_code)] |
| /// # use proptest::prelude::*; |
| /// # |
| /// # #[derive(Clone, Debug)] |
| /// # struct MyStruct { |
| /// # integer: u32, |
| /// # string: String, |
| /// # } |
| /// |
| /// prop_compose! { |
| /// fn my_struct_strategy(max_integer: u32) |
| /// (integer in 0..max_integer, string: String) |
| /// -> MyStruct { |
| /// MyStruct { integer, string } |
| /// } |
| /// } |
| /// # |
| /// # fn main() { } |
| /// ``` |
| /// |
| /// The second form is mostly the same, except that it takes _three_ argument |
| /// lists. The third argument list can see all values in both prior, which |
| /// permits producing strategies based on other strategies. |
| /// |
| /// ```rust,no_run |
| /// # #![allow(dead_code)] |
| /// use proptest::prelude::*; |
| /// |
| /// prop_compose! { |
| /// fn nearby_numbers()(centre in -1000..1000) |
| /// (a in centre-10..centre+10, |
| /// b in centre-10..centre+10) |
| /// -> (i32, i32) { |
| /// (a, b) |
| /// } |
| /// } |
| /// # |
| /// # fn main() { } |
| /// ``` |
| /// |
| /// However, the body of the function does _not_ have access to the second |
| /// argument list. If the body needs access to those values, they must be |
| /// passed through explicitly. |
| /// |
| /// ```rust,no_run |
| /// # #![allow(dead_code)] |
| /// use proptest::prelude::*; |
| /// |
| /// prop_compose! { |
| /// fn vec_and_index |
| /// (max_length: usize) |
| /// (vec in prop::collection::vec(1..10, 1..max_length)) |
| /// (index in 0..vec.len(), vec in Just(vec)) |
| /// -> (Vec<i32>, usize) |
| /// { |
| /// (vec, index) |
| /// } |
| /// } |
| /// # fn main() { } |
| /// ``` |
| /// |
| /// The second form is sugar around making a strategy tuple, calling |
| /// `prop_flat_map()`, then `prop_map()`. |
| /// |
| /// To give the function any modifier which isn't a visibility modifier, put it |
| /// in brackets before the `fn` token but after any visibility modifier. |
| /// |
| /// ```rust,no_run |
| /// # #![allow(dead_code)] |
| /// use proptest::prelude::*; |
| /// |
| /// prop_compose! { |
| /// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) |
| /// -> *const () { |
| /// v as *const () |
| /// } |
| /// } |
| /// # fn main() { } |
| /// ``` |
| /// |
| /// ## Comparison with Hypothesis' `@composite` |
| /// |
| /// `prop_compose!` makes it easy to do a lot of things you can do with |
| /// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), |
| /// but not everything. |
| /// |
| /// - You can't filter via this macro. For filtering, you need to make the |
| /// strategy the "normal" way and use `prop_filter()`. |
| /// |
| /// - More than two layers of strategies or arbitrary logic between the two |
| /// layers. If you need either of these, you can achieve them by calling |
| /// `prop_flat_map()` by hand. |
| #[macro_export] |
| macro_rules! prop_compose { |
| ($(#[$meta:meta])* |
| $vis:vis |
| $([$($modi:tt)*])? fn $name:ident $params:tt |
| ($($var:pat in $strategy:expr),+ $(,)?) |
| -> $return_type:ty $body:block) => |
| { |
| #[must_use = "strategies do nothing unless used"] |
| $(#[$meta])* |
| $vis |
| $($($modi)*)? fn $name $params |
| -> impl $crate::strategy::Strategy<Value = $return_type> { |
| let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); |
| $crate::strategy::Strategy::prop_map(strat, |
| move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) |
| } |
| }; |
| |
| ($(#[$meta:meta])* |
| $vis:vis |
| $([$($modi:tt)*])? fn $name:ident $params:tt |
| ($($var:pat in $strategy:expr),+ $(,)?) |
| ($($var2:pat in $strategy2:expr),+ $(,)?) |
| -> $return_type:ty $body:block) => |
| { |
| #[must_use = "strategies do nothing unless used"] |
| $(#[$meta])* |
| $vis |
| $($($modi)*)? fn $name $params |
| -> impl $crate::strategy::Strategy<Value = $return_type> { |
| let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); |
| let strat = $crate::strategy::Strategy::prop_flat_map( |
| strat, |
| move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| |
| $crate::proptest_helper!(@_WRAP ($($strategy2)*))); |
| $crate::strategy::Strategy::prop_map(strat, |
| move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) |
| } |
| }; |
| |
| ($(#[$meta:meta])* |
| $vis:vis |
| $([$($modi:tt)*])? fn $name:ident $params:tt |
| ($($arg:tt)+) |
| -> $return_type:ty $body:block) => |
| { |
| #[must_use = "strategies do nothing unless used"] |
| $(#[$meta])* |
| $vis |
| $($($modi)*)? fn $name $params |
| -> impl $crate::strategy::Strategy<Value = $return_type> { |
| let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); |
| $crate::strategy::Strategy::prop_map(strat, |
| move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) |
| } |
| }; |
| |
| ($(#[$meta:meta])* |
| $vis:vis |
| $([$($modi:tt)*])? fn $name:ident $params:tt |
| ($($arg:tt)+ $(,)?) |
| ($($arg2:tt)+ $(,)?) |
| -> $return_type:ty $body:block) => |
| { |
| #[must_use = "strategies do nothing unless used"] |
| $(#[$meta])* |
| $vis |
| $($($modi)*)? fn $name $params |
| -> impl $crate::strategy::Strategy<Value = $return_type> { |
| let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); |
| let strat = $crate::strategy::Strategy::prop_flat_map( |
| strat, |
| move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| |
| $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); |
| $crate::strategy::Strategy::prop_map(strat, |
| move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) |
| } |
| }; |
| } |
| |
| /// Similar to `assert!` from std, but returns a test failure instead of |
| /// panicking if the condition fails. |
| /// |
| /// This can be used in any function that returns a `Result<_, TestCaseError>`, |
| /// including the top-level function inside `proptest!`. |
| /// |
| /// Both panicking via `assert!` and returning a test case failure have the |
| /// same effect as far as proptest is concerned; however, the Rust runtime |
| /// implicitly prints every panic to stderr by default (including a backtrace |
| /// if enabled), which can make test failures unnecessarily noisy. By using |
| /// `prop_assert!` instead, the only output on a failing test case is the final |
| /// panic including the minimal test case. |
| /// |
| /// ## Example |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { |
| /// // Called with just a condition will print the condition on failure |
| /// prop_assert!((a*a + b*b).sqrt() <= a + b); |
| /// // You can also provide a custom failure message |
| /// prop_assert!((a*a + b*b).sqrt() <= a + b, |
| /// "Triangle inequality didn't hold for ({}, {})", a, b); |
| /// // If calling another function that can return failure, don't forget |
| /// // the `?` to propagate the failure. |
| /// assert_from_other_function(a, b)?; |
| /// } |
| /// } |
| /// |
| /// // The macro can be used from another function provided it has a compatible |
| /// // return type. |
| /// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { |
| /// prop_assert!((a*a + b*b).sqrt() <= a + b); |
| /// Ok(()) |
| /// } |
| /// # |
| /// # fn main() { triangle_inequality(); } |
| /// ``` |
| #[macro_export] |
| macro_rules! prop_assert { |
| ($cond:expr) => { |
| $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) |
| }; |
| |
| ($cond:expr, $($fmt:tt)*) => { |
| if !$cond { |
| let message = format!($($fmt)*); |
| let message = format!("{} at {}:{}", message, file!(), line!()); |
| return ::core::result::Result::Err( |
| $crate::test_runner::TestCaseError::fail(message)); |
| } |
| }; |
| } |
| |
| /// Similar to `assert_eq!` from std, but returns a test failure instead of |
| /// panicking if the condition fails. |
| /// |
| /// See `prop_assert!` for a more in-depth discussion. |
| /// |
| /// ## Example |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn concat_string_length(ref a in ".*", ref b in ".*") { |
| /// let cat = format!("{}{}", a, b); |
| /// // Use with default message |
| /// prop_assert_eq!(a.len() + b.len(), cat.len()); |
| /// // Can also provide custom message (added after the normal |
| /// // assertion message) |
| /// prop_assert_eq!(a.len() + b.len(), cat.len(), |
| /// "a = {:?}, b = {:?}", a, b); |
| /// } |
| /// } |
| /// # |
| /// # fn main() { concat_string_length(); } |
| /// ``` |
| #[macro_export] |
| macro_rules! prop_assert_eq { |
| ($left:expr, $right:expr) => {{ |
| let left = $left; |
| let right = $right; |
| $crate::prop_assert!( |
| left == right, |
| "assertion failed: `(left == right)` \ |
| \n left: `{:?}`,\n right: `{:?}`", |
| left, right); |
| }}; |
| |
| ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ |
| let left = $left; |
| let right = $right; |
| $crate::prop_assert!( |
| left == right, |
| concat!( |
| "assertion failed: `(left == right)` \ |
| \n left: `{:?}`, \n right: `{:?}`: ", $fmt), |
| left, right $($args)*); |
| }}; |
| } |
| |
| /// Similar to `assert_ne!` from std, but returns a test failure instead of |
| /// panicking if the condition fails. |
| /// |
| /// See `prop_assert!` for a more in-depth discussion. |
| /// |
| /// ## Example |
| /// |
| /// ``` |
| /// use proptest::prelude::*; |
| /// |
| /// proptest! { |
| /// # /* |
| /// #[test] |
| /// # */ |
| /// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { |
| /// // Use with default message |
| /// prop_assert_ne!(a, a + b); |
| /// // Can also provide custom message added after the common message |
| /// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); |
| /// } |
| /// } |
| /// # |
| /// # fn main() { test_addition(); } |
| /// ``` |
| #[macro_export] |
| macro_rules! prop_assert_ne { |
| ($left:expr, $right:expr) => {{ |
| let left = $left; |
| let right = $right; |
| prop_assert!( |
| left != right, |
| "assertion failed: `(left != right)`\ |
| \n left: `{:?}`,\n right: `{:?}`", |
| left, right); |
| }}; |
| |
| ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ |
| let left = $left; |
| let right = $right; |
| prop_assert!(left != right, concat!( |
| "assertion failed: `(left != right)`\ |
| \n left: `{:?}`,\n right: `{:?}`: ", $fmt), |
| left, right $($args)*); |
| }}; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! proptest_helper { |
| (@_WRAP ($a:tt)) => { $a }; |
| (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4) |
| }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5) |
| }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6) |
| }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt |
| $a4:tt $a5:tt $a6:tt $a7:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) |
| }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt |
| $a5:tt $a6:tt $a7:tt $a8:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) |
| }; |
| (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt |
| $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) |
| }; |
| (@_WRAP ($a:tt $($rest:tt)*)) => { |
| ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) |
| }; |
| (@_WRAPPAT ($item:pat)) => { $item }; |
| (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { |
| ($a0, $a1, $a2, $a3) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, |
| $a4:pat, $a5:pat, $a6:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, |
| $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, |
| $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) |
| }; |
| (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, |
| $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { |
| ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) |
| }; |
| (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { |
| ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) |
| }; |
| (@_WRAPSTR ($item:pat)) => { stringify!($item) }; |
| (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), |
| stringify!($a3), stringify!($a4)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), |
| stringify!($a4), stringify!($a5)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, |
| $a4:pat, $a5:pat, $a6:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), |
| stringify!($a4), stringify!($a5), stringify!($a6)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, |
| $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), |
| stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, |
| $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), |
| stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), |
| stringify!($a8)) |
| }; |
| (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, |
| $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { |
| (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), |
| stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), |
| stringify!($a8), stringify!($a9)) |
| }; |
| (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { |
| (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) |
| }; |
| // build a property testing block that when executed, executes the full property test. |
| (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ |
| $config.source_file = Some(file!()); |
| let mut runner = $crate::test_runner::TestRunner::new($config); |
| let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); |
| match runner.run( |
| &$crate::strategy::Strategy::prop_map( |
| $crate::proptest_helper!(@_WRAP ($($strategy)*)), |
| |values| $crate::sugar::NamedArguments(names, values)), |
| $($mod)* |$crate::sugar::NamedArguments( |
| _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| |
| { |
| let _: () = $body; |
| Ok(()) |
| }) |
| { |
| Ok(_) => (), |
| Err(e) => panic!("{}\n{}", e, runner), |
| } |
| }}; |
| // build a property testing block that when executed, executes the full property test. |
| (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ |
| $config.source_file = Some(file!()); |
| let mut runner = $crate::test_runner::TestRunner::new($config); |
| let names = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); |
| match runner.run( |
| &$crate::strategy::Strategy::prop_map( |
| $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), |
| |values| $crate::sugar::NamedArguments(names, values)), |
| $($mod)* |$crate::sugar::NamedArguments( |
| _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| |
| { |
| let _: () = $body; |
| Ok(()) |
| }) |
| { |
| Ok(_) => (), |
| Err(e) => panic!("{}\n{}", e, runner), |
| } |
| }}; |
| |
| // The logic below helps support `pat: type` in the proptest! macro. |
| |
| // These matchers define the actual logic: |
| (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; |
| (@_PAT [$s:ty] [$p:pat]) => { $p }; |
| (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; |
| (@_STRAT in [$s:expr] [$p:pat]) => { $s }; |
| (@_PAT in [$s:expr] [$p:pat]) => { $p }; |
| (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; |
| |
| // These matchers rewrite into the above extractors. |
| // We have to do this because `:` can't FOLLOW(pat). |
| // Note that this is not the full `pat` grammar... |
| // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. |
| (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { |
| $crate::proptest_helper!(@$cmd in [$s] [$p]) |
| }; |
| (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { |
| // Users can wrap in parens as a last resort. |
| $crate::proptest_helper!(@$cmd [$s] [$p]) |
| }; |
| (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [_]) |
| }; |
| (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) |
| }; |
| (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [ref $p]) |
| }; |
| (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [mut $p]) |
| }; |
| (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [$p]) |
| }; |
| (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { |
| $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) |
| }; |
| |
| // Rewrite, Inductive case: |
| (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { |
| ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[derive(Clone, Copy)] |
| pub struct NamedArguments<N, V>(#[doc(hidden)] pub N, #[doc(hidden)] pub V); |
| |
| impl<V: fmt::Debug> fmt::Debug for NamedArguments<&'static str, V> { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!(f, "{} = ", self.0)?; |
| self.1.fmt(f) |
| } |
| } |
| |
| macro_rules! named_arguments_tuple { |
| ($($ix:tt $argn:ident $argv:ident)*) => { |
| impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug |
| for NamedArguments<($($argn,)*),&'a ($($argv,)*)> |
| where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, |
| $($argv : 'a),* |
| { |
| #[allow(unused_assignments)] |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let mut first = true; |
| $( |
| if !first { |
| write!(f, ", ")?; |
| } |
| first = false; |
| fmt::Debug::fmt( |
| &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; |
| )* |
| Ok(()) |
| } |
| } |
| |
| impl<$($argn : Copy),*, $($argv),*> fmt::Debug |
| for NamedArguments<($($argn,)*), ($($argv,)*)> |
| where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* |
| { |
| #[allow(unused_assignments)] |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| let mut first = true; |
| $( |
| if !first { |
| write!(f, ", ")?; |
| } |
| first = false; |
| fmt::Debug::fmt( |
| &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; |
| )* |
| Ok(()) |
| } |
| } |
| } |
| } |
| |
| named_arguments_tuple!(0 AN AV); |
| named_arguments_tuple!(0 AN AV 1 BN BV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV |
| 5 FN FV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV |
| 5 FN FV 6 GN GV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV |
| 5 FN FV 6 GN GV 7 HN HV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV |
| 5 FN FV 6 GN GV 7 HN HV 8 IN IV); |
| named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV |
| 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); |
| |
| #[cfg(feature = "std")] |
| #[doc(hidden)] |
| pub fn force_no_fork(config: &mut crate::test_runner::Config) { |
| if config.fork() { |
| eprintln!( |
| "proptest: Forking/timeout not supported in closure-style \ |
| invocations; ignoring" |
| ); |
| |
| #[cfg(feature = "fork")] |
| { |
| config.fork = false; |
| } |
| #[cfg(feature = "timeout")] |
| { |
| config.timeout = 0; |
| } |
| assert!(!config.fork()); |
| } |
| } |
| |
| #[cfg(not(feature = "std"))] |
| pub fn force_no_fork(_: &mut crate::test_runner::Config) {} |
| |
| #[cfg(test)] |
| mod test { |
| use crate::strategy::Just; |
| |
| prop_compose! { |
| /// These are docs! |
| #[allow(dead_code)] |
| fn two_ints(relative: i32)(a in 0..relative, b in relative..) |
| -> (i32, i32) { |
| (a, b) |
| } |
| } |
| |
| prop_compose! { |
| /// These are docs! |
| #[allow(dead_code)] |
| pub fn two_ints_pub(relative: i32)(a in 0..relative, b in relative..) |
| -> (i32, i32) { |
| (a, b) |
| } |
| } |
| |
| prop_compose! { |
| /// These are docs! |
| #[allow(dead_code, improper_ctypes_definitions)] |
| pub [extern "C"] fn two_ints_pub_with_attrs |
| (relative: i32)(a in 0..relative, b in relative..) |
| -> (i32, i32) |
| { |
| (a, b) |
| } |
| } |
| |
| prop_compose! { |
| // The only modifier we can usefully put here is "unsafe", but we want |
| // to keep this crate unsafe-free, even nominally. "const" may |
| // eventually work, but is not allowed right now since the generated |
| // code contains local variables. `extern "C"` is accepted, even though |
| // the result is useless since the return type isn't C-compatible. |
| #[allow(dead_code, improper_ctypes_definitions)] |
| [extern "C"] fn with_modifier(relative: i32)(a in 0..relative) -> i32 { |
| a |
| } |
| } |
| |
| prop_compose! { |
| #[allow(dead_code)] |
| fn a_less_than_b()(b in 0..1000)(a in 0..b, b in Just(b)) |
| -> (i32, i32) { |
| (a, b) |
| } |
| } |
| |
| proptest! { |
| #[test] |
| fn test_something(a in 0u32..42u32, b in 1u32..10u32) { |
| prop_assume!(a != 41 || b != 9); |
| assert!(a + b < 50); |
| } |
| } |
| |
| prop_compose! { |
| #[allow(dead_code)] |
| fn single_closure_is_move(base: u64)(off in 0..10u64) -> u64 { |
| base + off |
| } |
| } |
| |
| prop_compose! { |
| #[allow(dead_code)] |
| fn double_closure_is_move |
| (base: u64) |
| (off1 in 0..10u64) |
| (off2 in off1..off1+10) |
| -> u64 |
| { |
| base + off2 |
| } |
| } |
| |
| #[allow(unused_variables)] |
| mod test_arg_counts { |
| use crate::strategy::Just; |
| |
| proptest! { |
| #[test] |
| fn test_1_arg(a in Just(0)) { } |
| #[test] |
| fn test_2_arg(a in Just(0), b in Just(0)) { } |
| #[test] |
| fn test_3_arg(a in Just(0), b in Just(0), c in Just(0)) { } |
| #[test] |
| fn test_4_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0)) { } |
| #[test] |
| fn test_5_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0)) { } |
| #[test] |
| fn test_6_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0)) { } |
| #[test] |
| fn test_7_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0)) { } |
| #[test] |
| fn test_8_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0), h in Just(0)) { } |
| #[test] |
| fn test_9_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0), h in Just(0), i in Just(0)) { } |
| #[test] |
| fn test_a_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0), h in Just(0), i in Just(0), |
| j in Just(0)) { } |
| #[test] |
| fn test_b_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0), h in Just(0), i in Just(0), |
| j in Just(0), k in Just(0)) { } |
| #[test] |
| fn test_c_arg(a in Just(0), b in Just(0), c in Just(0), |
| d in Just(0), e in Just(0), f in Just(0), |
| g in Just(0), h in Just(0), i in Just(0), |
| j in Just(0), k in Just(0), l in Just(0)) { } |
| } |
| } |
| |
| #[test] |
| fn named_arguments_is_debug_for_needed_cases() { |
| use super::NamedArguments; |
| |
| println!("{:?}", NamedArguments("foo", &"bar")); |
| println!("{:?}", NamedArguments(("foo",), &(1,))); |
| println!("{:?}", NamedArguments(("foo", "bar"), &(1, 2))); |
| println!("{:?}", NamedArguments(("a", "b", "c"), &(1, 2, 3))); |
| println!("{:?}", NamedArguments(("a", "b", "c", "d"), &(1, 2, 3, 4))); |
| println!( |
| "{:?}", |
| NamedArguments(("a", "b", "c", "d", "e"), &(1, 2, 3, 4, 5)) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments(("a", "b", "c", "d", "e", "f"), &(1, 2, 3, 4, 5, 6)) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments( |
| ("a", "b", "c", "d", "e", "f", "g"), |
| &(1, 2, 3, 4, 5, 6, 7) |
| ) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments( |
| ("a", "b", "c", "d", "e", "f", "g", "h"), |
| &(1, 2, 3, 4, 5, 6, 7, 8) |
| ) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments( |
| ("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
| &(1, 2, 3, 4, 5, 6, 7, 8, 9) |
| ) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments( |
| ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), |
| &(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) |
| ) |
| ); |
| println!( |
| "{:?}", |
| NamedArguments((("a", "b"), "c", "d"), &((1, 2), 3, 4)) |
| ); |
| } |
| |
| #[test] |
| fn oneof_all_counts() { |
| use crate::strategy::{Just as J, Strategy, TupleUnion, Union}; |
| |
| fn expect_count(n: usize, s: impl Strategy<Value = i32>) { |
| use crate::strategy::*; |
| use crate::test_runner::*; |
| use std::collections::HashSet; |
| |
| let mut runner = TestRunner::default(); |
| let mut seen = HashSet::new(); |
| for _ in 0..1024 { |
| seen.insert(s.new_tree(&mut runner).unwrap().current()); |
| } |
| |
| assert_eq!(n, seen.len()); |
| } |
| |
| fn assert_static<T>(v: TupleUnion<T>) -> TupleUnion<T> { |
| v |
| } |
| fn assert_dynamic<T: Strategy>(v: Union<T>) -> Union<T> { |
| v |
| } |
| |
| expect_count(1, prop_oneof![J(0i32)]); |
| expect_count(2, assert_static(prop_oneof![J(0i32), J(1i32),])); |
| expect_count(3, assert_static(prop_oneof![J(0i32), J(1i32), J(2i32),])); |
| expect_count( |
| 4, |
| assert_static(prop_oneof![J(0i32), J(1i32), J(2i32), J(3i32),]), |
| ); |
| expect_count( |
| 5, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| ]), |
| ); |
| expect_count( |
| 6, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| ]), |
| ); |
| expect_count( |
| 7, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| J(6i32), |
| ]), |
| ); |
| expect_count( |
| 8, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| J(6i32), |
| J(7i32), |
| ]), |
| ); |
| expect_count( |
| 9, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| J(6i32), |
| J(7i32), |
| J(8i32), |
| ]), |
| ); |
| expect_count( |
| 10, |
| assert_static(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| J(6i32), |
| J(7i32), |
| J(8i32), |
| J(9i32), |
| ]), |
| ); |
| expect_count( |
| 11, |
| assert_dynamic(prop_oneof![ |
| J(0i32), |
| J(1i32), |
| J(2i32), |
| J(3i32), |
| J(4i32), |
| J(5i32), |
| J(6i32), |
| J(7i32), |
| J(8i32), |
| J(9i32), |
| J(10i32), |
| ]), |
| ); |
| } |
| } |
| |
| #[cfg(all(test, feature = "timeout"))] |
| mod test_timeout { |
| proptest! { |
| #![proptest_config(crate::test_runner::Config { |
| fork: true, |
| .. crate::test_runner::Config::default() |
| })] |
| |
| // Ensure that the macro sets the test name properly. If it doesn't, |
| // this test will fail to run correctly. |
| #[test] |
| fn test_name_set_correctly_for_fork(_ in 0u32..1u32) { } |
| } |
| } |
| |
| #[cfg(test)] |
| mod another_test { |
| use crate::sugar; |
| |
| // Ensure that we can access the `[pub]` composed function above. |
| #[allow(dead_code)] |
| fn can_access_pub_compose() { |
| let _ = sugar::test::two_ints_pub(42); |
| let _ = sugar::test::two_ints_pub_with_attrs(42); |
| } |
| } |
| |
| #[cfg(test)] |
| mod ownership_tests { |
| #[cfg(feature = "std")] |
| proptest! { |
| #[test] |
| fn accept_ref_arg(ref s in "[0-9]") { |
| use crate::std_facade::String; |
| fn assert_string(_s: &String) {} |
| assert_string(s); |
| } |
| |
| #[test] |
| fn accept_move_arg(s in "[0-9]") { |
| use crate::std_facade::String; |
| fn assert_string(_s: String) {} |
| assert_string(s); |
| } |
| } |
| |
| #[derive(Debug)] |
| struct NotClone(); |
| const MK: fn() -> NotClone = NotClone; |
| |
| proptest! { |
| #[test] |
| fn accept_noclone_arg(nc in MK) { |
| let _nc2: NotClone = nc; |
| } |
| |
| #[test] |
| fn accept_noclone_ref_arg(ref nc in MK) { |
| let _nc2: &NotClone = nc; |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod closure_tests { |
| #[test] |
| fn test_simple() { |
| let x = 420; |
| |
| proptest!(|(y: i32)| { |
| assert!(x != y); |
| }); |
| |
| proptest!(|(y in 0..100)| { |
| println!("{}", y); |
| assert!(x != y); |
| }); |
| |
| proptest!(|(y: i32,)| { |
| assert!(x != y); |
| }); |
| |
| proptest!(|(y in 0..100,)| { |
| println!("{}", y); |
| assert!(x != y); |
| }); |
| } |
| |
| #[test] |
| fn test_move() { |
| let foo = Foo; |
| |
| proptest!(move |(x in 1..100, y in 0..100)| { |
| assert!(x + y > 0, "foo: {:?}", foo); |
| }); |
| |
| let foo = Foo; |
| proptest!(move |(x: (), y: ())| { |
| assert!(x == y, "foo: {:?}", foo); |
| }); |
| |
| #[derive(Debug)] |
| struct Foo; |
| } |
| |
| #[test] |
| #[should_panic] |
| #[allow(unreachable_code)] |
| fn fails_if_closure_panics() { |
| proptest!(|(_ in 0..1)| { |
| panic!() |
| }); |
| } |
| |
| #[test] |
| fn accepts_unblocked_syntax() { |
| proptest!(|(x in 0u32..10, y in 10u32..20)| assert!(x < y)); |
| proptest!(|(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); |
| } |
| |
| #[test] |
| fn accepts_custom_config() { |
| let conf = crate::test_runner::Config::default(); |
| |
| proptest!(conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); |
| proptest!(&conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); |
| proptest!(conf, move |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); |
| proptest!(conf, |(_x: u32, _y: u32)| { }); |
| proptest!(conf, move |(_x: u32, _y: u32)| { }); |
| |
| // Same as above, but with extra trailing comma |
| proptest!(conf, |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); |
| proptest!(&conf, |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); |
| proptest!(conf, move |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); |
| proptest!(conf, |(_x: u32, _y: u32,)| { }); |
| proptest!(conf, move |(_x: u32, _y: u32,)| { }); |
| } |
| } |
| |
| #[cfg(test)] |
| mod any_tests { |
| proptest! { |
| #[test] |
| fn test_something |
| ( |
| a: bool, |
| b in 25u8.., |
| c in 25u8.., |
| _d: (), |
| mut _e: (), |
| ref _f: (), |
| ref mut _g: (), |
| [_, _]: [(); 2], |
| ) { |
| if a {} // Assert bool. |
| assert!(b as usize + c as usize >= 50); |
| } |
| } |
| |
| // Test that the macro accepts some of the inputs we expect it to: |
| #[test] |
| fn proptest_ext_test() { |
| struct Y(pub u8); |
| |
| let _ = proptest_helper!(@_EXT _STRAT( _ : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( x : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( ref x : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( mut x : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( ref mut x : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( [_, _] : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( (&mut &Y(ref x)) : u8 )); |
| let _ = proptest_helper!(@_EXT _STRAT( x in 1..2 )); |
| |
| let proptest_helper!(@_EXT _PAT( _ : u8 )) = 1; |
| let proptest_helper!(@_EXT _PAT( _x : u8 )) = 1; |
| let proptest_helper!(@_EXT _PAT( mut _x : u8 )) = 1; |
| let proptest_helper!(@_EXT _PAT( ref _x : u8 )) = 1; |
| let proptest_helper!(@_EXT _PAT( ref mut _x : u8 )) = 1; |
| let proptest_helper!(@_EXT _PAT( [_, _] : u8 )) = [1, 2]; |
| let proptest_helper!(@_EXT _PAT( (&mut &Y(ref _x)) : u8 )) = &mut &Y(1); |
| let proptest_helper!(@_EXT _PAT( _x in 1..2 )) = 1; |
| } |
| } |