//- // Copyright 2017, 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , 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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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`. /// /// ```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, 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 { 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 { 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 { 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 { 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; $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)*); }}; } #[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(#[doc(hidden)] pub N, #[doc(hidden)] pub V); impl 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) { 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(v: TupleUnion) -> TupleUnion { v } fn assert_dynamic(v: Union) -> Union { 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; } }