Macro proptest::proptest

source ·
macro_rules! proptest {
    (#![proptest_config($config:expr)]
     $(
        $(#[$meta:meta])*
       fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block
    )*) => { ... };
    (#![proptest_config($config:expr)]
     $(
        $(#[$meta:meta])*
        fn $test_name:ident($($arg:tt)+) $body:block
    )*) => { ... };
    ($(
        $(#[$meta:meta])*
        fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block
    )*) => { ... };
    ($(
        $(#[$meta:meta])*
        fn $test_name:ident($($arg:tt)+) $body:block
    )*) => { ... };
    (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { ... };
    (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { ... };
    (|($($arg:tt)+)| $body:expr) => { ... };
    (move |($($arg:tt)+)| $body:expr) => { ... };
    ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { ... };
    ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { ... };
    ($config:expr, |($($arg:tt)+)| $body:expr) => { ... };
    ($config:expr, move |($($arg:tt)+)| $body:expr) => { ... };
}
Expand description

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());
  }
}

You can also use the normal argument syntax pattern: type as in:

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());
  }
}

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);
  }
}

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
  });
}