quickcheck ========== QuickCheck is a way to do property based testing using randomly generated input. This crate comes with the ability to randomly generate and shrink integers, floats, tuples, booleans, lists, strings, options and results. All QuickCheck needs is a property function—it will then randomly generate inputs to that function and call the property for each set of inputs. If the property fails (whether by a runtime error like index out-of-bounds or by not satisfying your property), the inputs are "shrunk" to find a smaller counter-example. The shrinking strategies for lists and numbers use a binary search to cover the input space quickly. ### Documentation The API is fully documented: [https://docs.rs/qcheck](https://docs.rs/qcheck). ### The `#[quickcheck]` attribute To make it easier to write QuickCheck tests, the `#[quickcheck]` attribute will convert a property function into a `#[test]` function. To use the `#[quickcheck]` attribute, you must import the `quickcheck` macro from the `quickcheck_macros` crate: ```rust #[cfg(test)] mod tests { fn reverse(xs: &[T]) -> Vec { let mut rev = vec!(); for x in xs { rev.insert(0, x.clone()) } rev } #[quickcheck] fn double_reversal_is_identity(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } } ``` ### Shrinking Shrinking is a crucial part of QuickCheck that simplifies counter-examples for your properties automatically. For example, if you erroneously defined a function for reversing vectors as: (my apologies for the contrived example) ```rust fn reverse(xs: &[T]) -> Vec { let mut rev = vec![]; for i in 1..xs.len() { rev.insert(0, xs[i].clone()) } rev } ``` And a property to test that `xs == reverse(reverse(xs))`: ```rust fn prop(xs: Vec) -> bool { xs == reverse(&reverse(&xs)) } quickcheck(prop as fn(Vec) -> bool); ``` Then without shrinking, you might get a counter-example like: ``` [quickcheck] TEST FAILED. Arguments: ([-17, 13, -12, 17, -8, -10, 15, -19, -19, -9, 11, -5, 1, 19, -16, 6]) ``` Which is pretty mysterious. But with shrinking enabled, you're nearly guaranteed to get this counter-example every time: ``` [quickcheck] TEST FAILED. Arguments: ([0]) ``` Which is going to be much easier to debug. ##### Cranking the Number of Tests Another approach is to just ask quickcheck to run properties more times. You can do this either via the [tests()](https://docs.rs/quickcheck/*/quickcheck/struct.QuickCheck.html#method.tests) method, or via the `QUICKCHECK_TESTS` environment variable. This will cause quickcheck to run for a much longer time. Unlike, the loop approach this will take a bounded amount of time, which makes it more suitable for something like a release cycle that wants to really hammer your software. ### Generating Structs It is very simple to generate structs in QuickCheck. Consider the following example, where the struct `Point` is defined: ```rust struct Point { x: i32, y: i32, } ``` In order to generate a random `Point` instance, you need to implement the trait `Arbitrary` for the struct `Point`: ```rust use qcheck::{Arbitrary, Gen}; impl Arbitrary for Point { fn arbitrary(g: &mut Gen) -> Point { Point { x: i32::arbitrary(g), y: i32::arbitrary(g), } } } ``` ## License Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org).