Modifier Reference

All modifiers interpreted by #[derive(Arbitrary)] are of the form #[proptest(..)], where the content between the parentheses follows the normal Rust attribute syntax.

Each modifier within the parentheses is independent, in that putting two modifiers in the same attribute is equivalent to having two #[proptest(..)] attributes with one modifier each.

For brevity, modifiers are sometimes referenced by name alone; e.g., “the weight modifier” refers to #[proptest(weight = nn)] and not some freestanding #[weight] attribute.

filter

Form: #[proptest(filter = F)] or #[proptest(filter(F))] where F is either a bare identifier (i.e., naming a function) or a Rust expression in a string. In either case, the parameter must evaluate to something which is Fn (&T) -> bool, where T is the type of the item being filtered.

Usable on: structs, enums, enum variants, fields

The filter modifier allows filtering values generated for a field via rejection sampling. Since rejection sampling is inefficient and interferes with shrinking, it should only be used for conditions that are very rare or are unfeasible to express otherwise. In many cases, strategy can be used to more directly express the desired behaviour without rejection sampling. See the documentation for prop_filter for more details.

The argument to the modifier must be a valid argument for the second parameter of prop_filter.

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
#[proptest(filter = "|segment| segment.start != segment.end")]
struct NonEmptySegment {
    start: i32,
    end: i32,
}

// Equivalent to the above
fn is_nonempty(segment: &NonEmptySegment) -> bool {
    segment.start != segment.end
}

#[derive(Debug, Arbitrary)]
#[proptest(filter = is_nomempty)]
struct NonEmptySegment {
    start: i32,
    end: i32,
}
}

As mentioned above, filtering should be avoided when it is reasonably possible to express a non-filtering strategy that achieves the same effect. For example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
struct BadExample {
    // Don't do this! Your tests will run more slowly and shrinking won't work
    // properly.
    #[proptest(filter = "|x| x % 2 == 0")]
    even_number: u32,
}

#[derive(Debug, Arbitrary)]
struct GoodExample {
    // Directly generate even numbers only by transforming the set of all
    // `u32`s and then mapping it to the set of even `u32`s.
    #[proptest(strategy = "any::<u32>().prop_map(|x| x / 2 * 2)")]
    even_number: u32,
}
}

no_bound

Form: #[proptest(no_bound)]

Usable on: generic type definitions and type parameters

Normally, when #[derive(Arbitrary)] is applied to an item with generic type parameter, every type parameter which is “used” (see below) is required to impl Arbitrary. For example, given a declaration like the following:


#![allow(unused)]
fn main() {
#[derive(Arbitrary)]
struct MyStruct<T> { /* ... */ }
}

Something like this will be generated:


#![allow(unused)]
fn main() {
impl<T> Arbitrary for MyStruct<T> where T: Arbitrary { /* ... */ }
}

Placing #[proptest(no_bound)] on a generic type parameter suppresses this. For example, the following removes the extra where T: Arbitrary:


#![allow(unused)]
fn main() {
#[derive(Arbitrary)]
struct MyStruct<#[proptest(no_bound)] T> { /* ... */ }
}

Placing #[proptest(no_bound)] on a generic type definition is equivalent to placing the same attribute on every type parameter.


#![allow(unused)]
fn main() {
#[derive(Arbitrary)]
#[proptest(no_bound)]
struct MyStruct<A, B, C> { /* ... */ }

// Equivalent to
#[derive[Arbitrary)]
struct MyStruct<
  #[proptest(no_bound)] A,
  #[proptest(no_bound)] B,
  #[proptest(no_bound)] C,
> { /* ... */ }
}

A type parameter is “used” if the following hold:

  • The enum or struct definition references it at least once, and that reference is not inside the type argument of a PhantomData.

  • The item referencing the type parameter does not have any proptest modifiers which replace the usual use of Arbitrary, such as skip or value.

Due to the above, #[proptest(no_bound)] is generally only needed when the type parameter is used in another type which does not itself have an Arbitrary mound on the type.

no_params

Form: #[proptest(no_params)]

Usable on: structs, enums, enum variants, fields

On a struct or enum, no_params causes the Arbitrary parameter type to be (). All automatic delegations to Arbitrary on members of the item use Default::default() for their parameters.

On an enum variant or field, suppresses the addition of any parameter for the variant or field to the parameters for the whole struct. If the variant or field automatically delegates to Arbitrary for its value, that Arbitrary call uses Default::default() for its own parameter.

See the param modifier for more information on how parameters work.

params

Form: #[proptest(params = T)] or #[proptest(params(T))], where T is either a bare identifier or Rust code inside a string. In either case, the value must name a concrete Rust type which implements Default.

Usable on: structs, enums, enum variants, fields

The Arbitrary trait specifies a Parameters type which is used to control generation. By default, the Parameters type is a tuple of the parameters which are automatically passed to other Arbitrary implementations.

If applied to a struct or enum, params completely replaces the Parameters type. Any automatic delegations to other Arbitrary implementations then use Default::default() as there is no automatic way to locate an appropriate value (if there even is any) within the params type.

If applied to an enum variant or field, params specifies the parameters type for just that item, as if its type had an Arbitrary implementation taking that type. In this case, either value or strategy must be specified since the parameter type will not generally be compatible with the normal Arbitrary invocation (and in cases where it is, params would be useless if not used).

Any expressions (such as in the value and strategy modifiers) underneath an item with the params modifier has access to a variable named params which is of the type passed in #[proptest(params = ..)].

Examples:


#![allow(unused)]
fn main() {
#[derive(Debug)]
struct WidgetRange(usize, usize);

impl Default for WidgetRange {
    fn default() -> Self { Self(0, 100) }
}

#[derive(Debug, Arbitrary)]
#[proptest(params(WidgetRange))]
struct WidgetCollection {
    #[proptest(strategy = "params.0 ..= params.1")]
    desired_widget_count: usize,
    // ...
}

// ...

proptest! {
    #[test]
    fn test_something(wc in any_with::<WidgetCollection>(WidgetRange(10, 20))) {
        assert!(wc.desired_widget_count >= 10 && wc.desired_widget_count <= 20);
    }
}
}

regex

Form: #[proptest(regex = "string")] or #[proptest(regex("string"))], where string is a regular expression. May also be invoked as #[proptest(regex(function_name))], where function_name is a no-argument function that returns an &'static str.

Usable on: fields

This modifier specifies to generate character or byte strings for a field which match a particular regular expression.

The regex modifier is equivalent to using the strategy modifier and enclosing the string in string_regex or bytes_regex. It can only be applied to fields of type String or Vec<u8>.

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
struct FileContent {
    #[proptest(regex = "[a-z0-9.]+")]
    name: String,
    #[proptest(regex = "([0-9]+\n)*")]
    content: Vec<u8>,
}
}

Form: #[proptest(skip)]

Usable on: enum variants

Annotating an enum variant with #[proptest(skip)] prevents proptest from generating that particular variant. This is useful when there is no sensible way to generate the variant or when you want to temporarily stop generating some variant during development.

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
enum DataSource {
    Memory(Vec<u8>),

    // There's no way to produce an "arbitrary" file handle, so we skip
    // generating this case.
    #[proptest(skip)]
    File(std::fs::File),
}
}

It is an error to annotate all inhabited variants of an enum with #[proptest(skip)] as this leaves proptest with no options to generate the enum.

strategy

Form: #[proptest(strategy = S)] or #[proptest(strategy = S)], where S is either a string containing a Rust expression which evaluates to an appropriate Strategy, or a bare identifier naming a function which, when called with no arguments, returns such a Strategy.

Usable on: enum variants, fields

By default, enum variants are generated by recursing into their definition as is done for struct declarations, and fields are generated by invoking Arbitrary on the field type to produce a Strategy. The strategy modifier allows to manually provide a custom strategy directly.

In the case of fields, the strategy must produce values of the same type as that field. For enum variants, it must produce values of the enum type itself and these values ought to be of the variant in question.

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
enum Token {
    Delimitation {
        // This field is still generated via Arbitrary
        delimiter: Delimiter,

        // But for this field we use a custom strategy
        #[proptest(strategy = "1..10")]
        count: u32,

        // Here we also use a custom strategy, generated by the function
        // `offset_strategy`.
        #[proptest(strategy = offset_strategy)]
        offset: u32,
    },

    // Specify how to generate the whole enum variant
    #[proptest(strategy = "\"[a-zA-Z]+\".prop_map(Token::Word)")]
    Word(String),
}

#[derive(Debug, Arbitrary)]
enum Delimiter { /* ... */ }

fn offset_strategy() -> impl Strategy<Value = u32> {
  0..100
}
}

value

Form: #[proptest(value = V)] or #[proptest(value(V))], where V can be: (a) a Rust expression enclosed in a string; (b) another literal, or (c) a bare identifier naming a no-argument function.

Usable on: enum variants, fields

The value modifier indicates that proptest should use the given expression or function to produce a value for the field, instead of going through the usual value generation machinery.

The argument to value is directly used as an expression for the field value or enum variant to be generated, except that in the third form where it is a bare identifier, it is called as a no-argument function to produce the value.

Using value is equivalent to using strategy and enclosing the value in LazyJust.

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
struct EventCounter {
    // We always start with the first two fields set to 0/None
    #[proptest(value = 0)]
    number_seen: u64,

    #[proptest(value = "None")]
    last_seen_time: Option<Instant>,

    // This field is generated normally
    max_events: u64,
}
}

weight

Form: #[proptest(weight = W)] or #[proptest(weight(W))], where W is an expression evaluating to a u32. weight may also be abbreviated to w, as in #[proptest(w = W)].

Usable on: enum variants

The weight modifier determines how likely proptest is to generate a particular enum variant. Weights are relative to each other; for example, a weight = 3 variant is 50% more likely to be generated than a weight = 2 variant and three times as likely to be generated as a weight = 1 variant.

Variants with no weight modifier are equivalent to being annotated #[proptest(weight = 1)].

Example:


#![allow(unused)]
fn main() {
#[derive(Debug, Arbitrary)]
enum FilterOption {
    KeepAll,
    DiscardAll,

    // This option is presumably harder for the code to handle correctly,
    // so we generate it more frequently than the other options.
    #[proptest(weight = 3)]
    OnlyMatching(String),
}
}