Core sampling strategies, along with useful implementations for samplers on
types from [std
] and the [quickcheck
] crate.
The core of this library is the [Sample
] trait, which uses [Random
] to
generate arbitrary values from a sampled Output
type with a custom
"sampling strategy". It also defines a procedure for "shrinking" generated
values, which can be used to generate simple counterexamples against
expected properties.
This library is generally intended for usage alongside the sample_test
crate. See that crate for macros and examples for using samplers within unit
tests.
Sampling Strategies
The simplest [Sample
] implementation is for [Range
]. It is a sampler
that generates values uniformly from the given range, and attempts to shrink
down to the start of the range:
use ;
let s = 10..100;
let v = s.generate;
assert!;
let mut shrunk = s.shrink;
assert_eq!;
if v > s.start
Samplers are defined for tuples of samplers up to size 8, which can be
used in concert with [Sample::try_convert
] to combine samplers into a
sampler for a larger type:
use ;
let sampler = .try_convert;
For an example of sampling an enum
, see [sampler_choice
].
Prior Work
This crate is heavily inspired by [quickcheck
]. It builds upon it, in
particular by defining samplers for [Arbitrary
] (see [arbitrary
]). Many
methods and structs in here were derived from their [quickcheck
]
counterparts.
It attempts to iterate and improve on the [quickcheck
] core idea:
- Allow definition of multiple sampling strategies for the same type.
- No need to define newtypes for custom sampling strategies.
There is still some cruft and weirdness from this early attempt to combine these worldviews:
- The concept of
size
isn't really necessary in a world with sampling strategies. - The [
Random
] struct could probably just become a type definition around the underlyingrng
.
The core idea for sampling "strategies" comes from proptest
, which
uses macros instead of combinators for composition, and has more complex
shrinking functionality.