Create tests that sample arbitrary data to produce counterexamples for a given proposition:
use sample_std::VecSampler;
use sample_test::{sample_test, TestResult};
#[sample_test]
fn age_range(#[sample(VecSampler { el: 1..25, length: 0..50 })] ages: Vec<u8>) -> TestResult {
if ages.iter().all(|a| *a < 5) {
TestResult::discard()
} else {
TestResult::from_bool(ages.iter().all(|a| *a < 25))
}
}
This library was heavily inspired by quickcheck
and proptest
.
Here's where it differs:
quickcheck
works at the type level, and thus creating a new sampling strategy requires an entirely new type. This gets painfully verbose with complex types and many different sampling strategies.proptest
uses macros to create strategies, and creates a tree of seed values to shrink data. This tree can get very large for recursive data, and macros can be a pain to work with.
This library attempts to split the difference. It allows user-defined Sample
strategies which are fed into tests. Shrinking, like with quickcheck
,
operates directly on generated values. This avoids the need to create and
maintain the seed tree used by proptest
, and allows this library to
scale up to larger generated data sizes.
Instead of macros, this library and any downstream users rely heavily on
Sample
combinators. This is inspired by Iterator
composition which
is very performant and concise, all without the need for any macros.
The tradeoffs are:
sample-test
is slightly more complicated thanquickcheck
, with the benefit of easier definition of sampling strategies.sample-test
is not as good at shrinking asproptest
as it does not record the seed values that were used to generate a given output.