//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use core::fmt; use crate::strategy::Strategy; //============================================================================== // Arbitrary trait //============================================================================== /// Arbitrary determines a canonical [`Strategy`] for the implementing type. /// /// It provides the method `arbitrary_with` which generates a `Strategy` for /// producing arbitrary values of the implementing type *(`Self`)*. In general, /// these strategies will produce the entire set of values possible for the /// type, up to some size limitation or constraints set by their parameters. /// When this is not desired, strategies to produce the desired values can be /// built by combining [`Strategy`]s as described in the crate documentation. /// /// This trait analogous to /// [Haskell QuickCheck's implementation of `Arbitrary`][HaskellQC]. /// In this interpretation of `Arbitrary`, `Strategy` is the equivalent of /// the `Gen` monad. Unlike in QuickCheck, `Arbitrary` is not a core component; /// types do not need to implement `Arbitrary` unless one wants to use /// [`any`](fn.any.html) or other free functions in this module. /// /// `Arbitrary` currently only works for types which represent owned data as /// opposed to borrowed data. This is a fundamental restriction of `proptest` /// which may be lifted in the future as the [generic associated types (GAT)] /// feature of Rust is implemented and stabilized. /// /// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 /// /// [`Strategy`]: ../strategy/trait.Strategy.html /// /// [HaskellQC]: /// https://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck-Arbitrary.html pub trait Arbitrary: Sized + fmt::Debug { /// The type of parameters that [`arbitrary_with`] accepts for configuration /// of the generated [`Strategy`]. Parameters must implement [`Default`]. /// /// [`arbitrary_with`]: trait.Arbitrary.html#tymethod.arbitrary_with /// /// [`Strategy`]: ../strategy/trait.Strategy.html /// [`Default`]: /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html type Parameters: Default; /// Generates a [`Strategy`] for producing arbitrary values /// of type the implementing type (`Self`). /// /// Calling this for the type `X` is the equivalent of using /// [`X::arbitrary_with(Default::default())`]. /// /// This method is defined in the trait for optimization for the /// default if you want to do that. It is a logic error to not /// preserve the semantics when overriding. /// /// [`Strategy`]: ../strategy/trait.Strategy.html /// [`X::arbitrary_with(Default::default())`]: /// trait.Arbitrary.html#tymethod.arbitrary_with fn arbitrary() -> Self::Strategy { Self::arbitrary_with(Default::default()) } /// Generates a [`Strategy`] for producing arbitrary values of type the /// implementing type (`Self`). The strategy is passed the arguments given /// in args. /// /// If you wish to use the [`default()`] arguments, /// use [`arbitrary`] instead. /// /// [`Strategy`]: ../strategy/trait.Strategy.html /// /// [`arbitrary`]: trait.Arbitrary.html#method.arbitrary /// /// [`default()`]: /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html fn arbitrary_with(args: Self::Parameters) -> Self::Strategy; /// The type of [`Strategy`] used to generate values of type `Self`. /// /// [`Strategy`]: ../strategy/trait.Strategy.html type Strategy: Strategy; } //============================================================================== // Type aliases for associated types //============================================================================== /// `StrategyFor` allows you to mention the type of [`Strategy`] for the input /// type `A` without directly using associated types or without resorting to /// existential types. This way, if implementation of [`Arbitrary`] changes, /// your tests should not break. This can be especially beneficial when the /// type of `Strategy` that you are dealing with is very long in name /// (the case with generics). /// /// [`Arbitrary`]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html pub type StrategyFor = ::Strategy; /// `ParamsFor` allows you to mention the type of [`Parameters`] for the input /// type `A` without directly using associated types or without resorting to /// existential types. This way, if implementation of [`Arbitrary`] changes, /// your tests should not break. /// /// [`Parameters`]: trait.Arbitrary.html#associatedtype.Parameters /// [`Arbitrary`]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html pub type ParamsFor = ::Parameters; //============================================================================== // Free functions that people should use //============================================================================== /// Generates a [`Strategy`] producing [`Arbitrary`][trait Arbitrary] values of /// `A`. Unlike [`arbitrary`][fn arbitrary], it should be used for being /// explicit on what `A` is. For clarity, this may be a good idea. /// /// Use this version instead of [`arbitrary`][fn arbitrary] if you want to be /// clear which type you want to generate a `Strategy` for, or if you don't /// have an anchoring type for type inference to work with. /// /// If you want to customize how the strategy is generated, use /// [`any_with::(args)`] where `args` are any arguments accepted by /// the `Arbitrary` impl in question. /// /// # Example /// /// The function can be used as: /// /// ```rust /// use proptest::prelude::*; /// /// proptest! { /// fn reverse_reverse_is_identity(ref vec in any::>()) { /// let vec2 = vec.iter().cloned().rev().rev().collect::>(); /// prop_assert_eq!(vec, &vec2); /// } /// } /// /// fn main() { /// reverse_reverse_is_identity(); /// } /// ``` /// /// [`any_with::(args)`]: fn.any_with.html /// [fn arbitrary]: fn.arbitrary.html /// [trait Arbitrary]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html #[must_use = "strategies do nothing unless used"] pub fn any() -> StrategyFor { // ^-- We use a shorter name so that turbofish becomes more ergonomic. A::arbitrary() } /// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the /// given configuration arguments passed in `args`. Unlike [`arbitrary_with`], /// it should be used for being explicit on what `A` is. /// For clarity, this may be a good idea. /// /// Use this version instead of [`arbitrary_with`] if you want to be clear which /// type you want to generate a `Strategy` for, or if you don't have an anchoring /// type for type inference to work with. /// /// If you don't want to specify any arguments and instead use the default /// behavior, you should use [`any::()`]. /// /// # Example /// /// The function can be used as: /// /// ```rust /// use proptest::prelude::*; /// use proptest::collection::size_range; /// /// proptest! { /// fn reverse_reverse_is_identity /// (ref vec in any_with::>(size_range(1000).lift())) /// { /// let vec2 = vec.iter().cloned().rev().rev().collect::>(); /// prop_assert_eq!(vec, &vec2); /// } /// } /// /// fn main() { /// reverse_reverse_is_identity(); /// } /// ``` /// /// [`any::()`]: fn.any.html /// [`arbitrary_with`]: fn.arbitrary_with.html /// [`Arbitrary`]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html #[must_use = "strategies do nothing unless used"] pub fn any_with(args: ParamsFor) -> StrategyFor { // ^-- We use a shorter name so that turbofish becomes more ergonomic. A::arbitrary_with(args) } /// Generates a [`Strategy`] producing [`Arbitrary`] values of `A`. /// Works better with type inference than [`any::()`]. /// /// With this version, you shouldn't need to specify any of the (many) type /// parameters explicitly. This can have a positive effect on type inference. /// However, if you want specify `A`, you should use [`any::()`] instead. /// /// For clarity, it is often a good idea to specify the type generated, and /// so using [`any::()`] can be a good idea. /// /// If you want to customize how the strategy is generated, use /// [`arbitrary_with(args)`] where `args` is of type /// `::Parameters`. /// /// # Example /// /// The function can be used as: /// /// ```rust /// extern crate proptest; /// use proptest::arbitrary::{arbitrary, StrategyFor}; /// /// fn gen_vec_usize() -> StrategyFor> { /// arbitrary() /// } /// /// # fn main() {} /// ``` /// /// [`arbitrary_with(args)`]: fn.arbitrary_with.html /// [`any::()`]: fn.any.html /// [`Arbitrary`]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html #[must_use = "strategies do nothing unless used"] pub fn arbitrary() -> S where // The backlinking here cause an injection which helps type inference. S: Strategy, A: Arbitrary, { A::arbitrary() } /// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the /// given configuration arguments passed in `args`. /// Works better with type inference than [`any_with::(args)`]. /// /// With this version, you shouldn't need to specify any of the (many) type /// parameters explicitly. This can have a positive effect on type inference. /// However, if you want specify `A`, you should use /// [`any_with::(args)`] instead. /// /// For clarity, it is often a good idea to specify the type generated, and /// so using [`any_with::(args)`] can be a good idea. /// /// If you don't want to specify any arguments and instead use the default /// behavior, you should use [`arbitrary()`]. /// /// # Example /// /// The function can be used as: /// /// ```rust /// extern crate proptest; /// use proptest::arbitrary::{arbitrary_with, StrategyFor}; /// use proptest::collection::size_range; /// /// fn gen_vec_10_u32() -> StrategyFor> { /// arbitrary_with(size_range(10).lift()) /// } /// /// # fn main() {} /// ``` /// /// [`any_with::(args)`]: fn.any_with.html /// [`arbitrary()`]: fn.arbitrary.html /// [`Arbitrary`]: trait.Arbitrary.html /// [`Strategy`]: ../strategy/trait.Strategy.html #[must_use = "strategies do nothing unless used"] pub fn arbitrary_with(args: P) -> S where P: Default, // The backlinking here cause an injection which helps type inference. S: Strategy, A: Arbitrary, { A::arbitrary_with(args) }