/// [`Strategy`] generators for property tests. /// /// most importantly, this provides a [`TestInput`] type and an accompanying [`input_strategy()`] /// that can be used to generate inputs for a property test. /// /// use [`values_that_need_truncation()`] and [`values_that_fit()`] for values that do or do not /// need to be limited, respectively. use { proptest::{prop_compose, strategy::Strategy}, std::ops::Not, }; /// an input to a property test. #[derive(Debug)] pub struct TestInput { // the value whose contents we will limit. pub value: String, // the length we will limit to. pub length: usize, } prop_compose! { /// a strategy that generates [`TestInput`] values. pub fn input_strategy() ( value in value_strategy(), length in length_strategy() ) -> TestInput { TestInput { value, length } } } fn length_strategy() -> impl Strategy { 4..2048_usize } /// returns a [`Strategy`] for strings of lowercase alphabetic characters. /// /// NB: this string may be empty. pub fn value_strategy() -> impl Strategy { "[a-z]{0,1024}" } /// returns a [`Strategy`] for *non-empty* string of lowercase alphabetic characters. #[allow(dead_code)] // this is used by property tests outside of this file. pub fn value_strategy_non_empty() -> impl Strategy { const REASON: &'static str = "value should be non-empty"; let is_not_empty = |s: &String| s.is_empty().not(); value_strategy().prop_filter(REASON, is_not_empty) } /// returns a [`Strategy`] that creates values that fit into the target width. /// /// inputs generated by this function will always have a value that fits in the target length. #[allow(dead_code)] // this is used by property tests outside of this file. pub fn values_that_fit() -> impl Strategy { const REASON: &'static str = "test input should be shorter than its target length"; let fits = |input: &TestInput| match input { TestInput { value, length } if value.len() <= *length => true, _ => false, }; input_strategy().prop_filter(REASON, fits) } /// returns a [`Strategy`] that creates values that will need to be truncated. /// /// inputs generated by this function will always have a value longer than the target length. pub fn values_that_need_truncation() -> impl Strategy { const REASON: &'static str = "test input should be longer than its target length"; let needs_truncation = |input: &TestInput| match input { TestInput { value, length } if value.len() > *length => true, _ => false, }; input_strategy().prop_filter(REASON, needs_truncation) }