### Example test failure output Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Sample output showing a panic caused by invalid byte indexing on unicode input. ```text thread 'main' panicked at 'Test failed: byte index 4 is not a char boundary; it is inside 'ௗ' (bytes 2..5) of `aAௗ0㌀0`; minimal failing input: s = "aAௗ0㌀0" successes: 102 local rejects: 0 global rejects: 0 ' ``` -------------------------------- ### Testing a function with two arguments using tuple strategy Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/compound-strategies.md This example shows how to test a function `add` that takes two `i32` arguments. It uses a tuple of two range strategies `(0..1000i32, 0..1000i32)` to generate pairs of integers. The generated tuple is then destructured to pass individual arguments to the `add` function within the test. ```rust # extern crate proptest; use proptest::test_runner::TestRunner; fn add(a: i32, b: i32) -> i32 { a + b } #[test] # fn dummy() {} // Doctests don't build `#[test]` functions, so we need this fn test_add() { let mut runner = TestRunner::default(); // Combine our two inputs into a strategy for one tuple. Our test // function then destructures the generated tuples back into separate // `a` and `b` variables to be passed in to `add()`. runner.run(&(0..1000i32, 0..1000i32), |(a, b)| { let sum = add(a, b); assert!(sum >= a); assert!(sum >= b); Ok(()) }).unwrap(); } # fn main() { test_add(); } ``` -------------------------------- ### Rust 2015 Crate Setup Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/getting-started.md For Rust 2015 crates, include this `extern crate` declaration at the top of your crate. ```rust #[cfg(test)] extern crate proptest; ``` -------------------------------- ### Debug test input with println! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Insert a print statement at the start of a test function to observe the values generated by proptest during execution. ```rust # let (y, m, d) = (0, 10, 1); println!("y = {}, m = {}, d = {}", y, m, d); ``` -------------------------------- ### Define Order Strategy with prop_compose! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/macro-prop-compose.md Use prop_compose! to define strategies for generating Order structs. This example shows composing a strategy for an order ID with strategies for item and quantity. ```rust prop_compose! { fn arb_order_id()(id in any::()) -> String { id.to_string() } } prop_compose! { fn arb_order(max_quantity: u32) (id in arb_order_id(), item in "[a-z]*", quantity in 1..max_quantity) -> Order { Order { id, item, quantity } } } ``` -------------------------------- ### Debugging Proptest Failure Output Source: https://github.com/proptest-rs/proptest/blob/main/README.md When a proptest fails, it provides a minimal failing input. This text output shows an example of such a failure, indicating the specific year, month, and day that caused the assertion to fail and the location of the failure. ```text thread 'main' panicked at 'Test failed: assertion failed: `(left == right)` (left: `(0, 10, 1)`, right: `(0, 0, 1)`) at examples/dateparser_v2.rs:46; minimal failing input: y = 0, m = 10, d = 1 successes: 2 local rejects: 0 global rejects: 0 ', examples/dateparser_v2.rs:33 note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` -------------------------------- ### Naïve Recursive Strategy Generation Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/recursive.md An example of an incorrect approach to generating recursive data structures that leads to unconditional recursion. ```rust # extern crate proptest; use std::collections::HashMap; use proptest::prelude::*; #[derive(Clone, Debug)] enum Json { Null, Bool(bool), Number(f64), String(String), Array(Vec), Map(HashMap), } fn arb_json() -> impl Strategy { prop_oneof![ Just(Json::Null), any::().prop_map(Json::Bool), any::().prop_map(Json::Number), ".*".prop_map(Json::String), prop::collection::vec(arb_json(), 0..10).prop_map(Json::Array), prop::collection::hash_map( ".*", arb_json(), 0..10).prop_map(Json::Map), ].boxed() } ``` -------------------------------- ### Define a struct with invariants Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/arbitrary.md A struct example requiring manual validation logic to ensure internal invariants are maintained. ```rust #[derive(Debug)] struct Range { lower: i32, upper: i32, } impl Range { pub fn new(lower: i32, upper: i32) -> Option { if lower <= upper { Some(Self { lower, upper }) } else { None } } } ``` -------------------------------- ### Sample Strategies for Collections Source: https://context7.com/proptest-rs/proptest/llms.txt Use Index and Selector to pick elements from runtime-sized collections. Subsequence generates ordered subsets from a given collection. ```rust use proptest::prelude::*; use proptest::sample::{Index, Selector}; use std::collections::HashSet; proptest! { #[test] fn test_index_strategy( // Generate collection and index separately, then combine items in prop::collection::vec("[a-z]+", 5..20), index in any::() ) { // Index automatically scales to collection size let selected = index.get(&items); prop_assert!(items.contains(selected)); } #[test] fn test_selector_with_set( // Selector works with any IntoIterator, including HashSet names in prop::collection::hash_set("[a-z]{3,8}", 5..15), selector in any::() ) { // Select from a non-indexable collection let chosen = selector.select(&names); prop_assert!(names.contains(chosen)); } #[test] fn test_subsequence( // Generate a subsequence (subset preserving order) sub in proptest::sample::subsequence( vec!["a", "b", "c", "d", "e", "f"], 2..5 ) ) { prop_assert!(sub.len() >= 2 && sub.len() < 5); // Elements are in original order let valid = ["a", "b", "c", "d", "e", "f"]; for window in sub.windows(2) { let pos0 = valid.iter().position(|&x| x == window[0]).unwrap(); let pos1 = valid.iter().position(|&x| x == window[1]).unwrap(); prop_assert!(pos0 < pos1); } } } ``` -------------------------------- ### Basic Slice and Index Generation with Filter Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/higher-order.md Demonstrates an initial attempt to generate a slice and an index using a filter. This approach can lead to many rejections and infrequent generation of smaller collections. ```rust # extern crate proptest; use proptest::prelude::* fn some_function(stuff: &[String], index: usize) { /* do stuff */ } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_some_function( stuff in prop::collection::vec(".*", 1..100), index in 0..100usize ) { prop_assume!(index < stuff.len()); some_function(&stuff, index); } } ``` -------------------------------- ### Generate Random Values with Strategies Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/strategy-basics.md Demonstrates generating random i32 and string values using proptest strategies and TestRunner. Ensure necessary imports are included. ```rust extern crate proptest; use proptest::test_runner::TestRunner; use proptest::strategy::{Strategy, ValueTree}; fn main() { let mut runner = TestRunner::default(); let int_val = (0..100i32).new_tree(&mut runner).unwrap(); let str_val = "[a-z]{1,4}\p{Cyrillic}{1,4}\p{Greek}{1,4}" .new_tree(&mut runner).unwrap(); println!("int_val = {}, str_val = {}", int_val.current(), str_val.current()); } ``` -------------------------------- ### Initialize SUT State for State Machine Test Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Implement this function to initialize the System Under Test (SUT) state. Use `ref_state` if your `ReferenceStateMachine::init_state` uses a non-constant strategy to ensure consistent initial states. ```rust fn init_test(ref_state: &Self::Reference::State) -> Self::SystemUnderTest ``` -------------------------------- ### Configure Proptest dependencies Source: https://context7.com/proptest-rs/proptest/llms.txt Add these dependencies to your Cargo.toml file to enable core functionality, derive macros, and state machine testing. ```toml [dev-dependencies] proptest = "1.11.0" # Optional: for deriving Arbitrary proptest-derive = "0.8.0" # Optional: for state machine testing proptest-state-machine = "0.8.0" ``` -------------------------------- ### Define and Run a State Machine Test with proptest Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Use the `prop_state_machine!` macro to define and run a state machine test. Specify the test name, the number of transitions, and the `StateMachineTest` implementation. ```rust prop_state_machine! { #[test] fn name_of_the_test(sequential 1..20 => MyStateMachineTest); } ``` -------------------------------- ### E0027: Invalid #[proptest(filter = "expr")] Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/errors.md This error is raised for invalid forms of `#[proptest(filter = "expr")]`. This includes missing arguments, incorrect syntax, or non-valid Rust expressions within the string, such as the example provided. ```rust #[derive(Debug, Arbitrary)] struct Foo { #[proptest(filter = "> 3")] // String content is not an expression big_number: u128, } ``` -------------------------------- ### E0023: Invalid type in #[proptest(params = "type")] Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/errors.md This error is triggered by an invalid type string in the `#[proptest(params = "type")]` attribute. Ensure the type string is valid Rust syntax and correctly formatted, with a missing '>' in the example. ```rust #[derive(Debug, Arbitrary)] #[proptest(params = "Vec' struct Foo(u32); ``` -------------------------------- ### Apply Transition and Check Post-conditions in State Machine Test Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Apply a transition to the SUT state and check post-conditions. You can use `ref_state` for comparison after applying the transition. ```rust fn apply( mut state: Self::SystemUnderTest, ref_state: &Self::Reference::State, transition: Transition ) -> Self::SystemUnderTest ``` -------------------------------- ### Generate String from u32 using prop_map Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/transforming-strategies.md Use `any::().prop_map(|v| v.to_string())` to generate a `u32`, convert it to a `String`, and ensure shrinking occurs based on the `u32` value. ```rust extern crate proptest; // Grab `Strategy`, shorter namespace prefix, and the macros use proptest::prelude::*; fn do_stuff(v: String) { let i: u32 = v.parse().unwrap(); let s = i.to_string(); assert_eq!(s, v); } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_do_stuff(v in any::().prop_map(|v| v.to_string())) { do_stuff(v); } } # fn main() { test_do_stuff(); } ``` -------------------------------- ### Find minimal failing case with simplify and complicate Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/shrinking-basics.md Uses a loop with simplify() and complicate() to binary search for the exact boundary condition where a function fails. ```rust # extern crate proptest; use proptest::test_runner::TestRunner; use proptest::strategy::{Strategy, ValueTree}; fn some_function(v: i32) -> bool { // Do a bunch of stuff, but crash if v > 500 // assert!(v <= 500); // But return a boolean instead of panicking for simplicity v <= 500 } // We know the function is broken, so use a purpose-built main function to // find the breaking point. fn main() { let mut runner = TestRunner::default(); for _ in 0..256 { let mut val = (0..10000i32).new_tree(&mut runner).unwrap(); if some_function(val.current()) { // Test case passed continue; } // We found our failing test case, simplify it as much as possible. loop { if !some_function(val.current()) { // Still failing, find a simpler case if !val.simplify() { // No more simplification possible; we're done break; } } else { // Passed this input, back up a bit if !val.complicate() { break; } } } println!("The minimal failing case is {}", val.current()); assert_eq!(501, val.current()); return; } panic!("Didn't find a failing test case"); } ``` -------------------------------- ### Initialize reference state machine Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Defines the initial state strategy for the state machine. ```rust fn init_state() -> BoxedStrategy ``` -------------------------------- ### Demonstrate ValueTree simplification Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/shrinking-basics.md Iteratively calls simplify() on a generated string value to observe how the output shrinks while maintaining strategy constraints. ```rust # extern crate proptest; use proptest::test_runner::TestRunner; use proptest::strategy::{Strategy, ValueTree}; fn main() { let mut runner = TestRunner::default(); let mut str_val = "[a-z]{1,4}\p{Cyrillic}{1,4}\p{Greek}{1,4}" .new_tree(&mut runner).unwrap(); println!("str_val = {}", str_val.current()); while str_val.simplify() { println!(" = {}", str_val.current()); } } ``` -------------------------------- ### Run Proptest with Forking via Environment Variable Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/forking.md Enable forking for all proptest tests by setting the PROPTEST_FORK environment variable. Individual tests can still opt out. ```sh # Run all the proptest tests in subprocesses with no timeout. # Individual tests can still opt out by setting `fork: false` in their # own configuration. PROPTEST_FORK=true cargo test ``` -------------------------------- ### Configure failure persistence Source: https://context7.com/proptest-rs/proptest/llms.txt Manage how failing test cases are saved using proptest! macro configurations. Persistence can be enabled with custom paths or disabled entirely. ```rust use proptest::prelude::*; proptest! { // Failures are saved to proptest-regressions//.txt #[test] fn test_with_persistence(x in any::()) { // If this fails, the seed is saved prop_assert!(x != 42); } } // Custom persistence location proptest! { #![proptest_config(ProptestConfig { failure_persistence: Some(Box::new( proptest::test_runner::FileFailurePersistence::WithSource("custom_regressions") )), ..ProptestConfig::default() })] #[test] fn test_custom_persistence(x in any::()) { prop_assert!(x < u32::MAX); } } // Disable persistence proptest! { #![proptest_config(ProptestConfig { failure_persistence: None, ..ProptestConfig::default() })] #[test] fn test_no_persistence(x in any::()) { prop_assert!(x.count_ones() <= 32); } } ``` -------------------------------- ### Define property tests with proptest! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/macro-proptest.md Uses the proptest! macro to define a test function with input strategies for parameters. ```rust # extern crate proptest; use proptest::prelude::*; fn add(a: i32, b: i32) -> i32 { a + b } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_add(a in 0..1000i32, b in 0..1000i32) { let sum = add(a, b); assert!(sum >= a); assert!(sum >= b); } } # # fn main() { test_add(); } ``` -------------------------------- ### Proptest Value Reduction Trace Source: https://github.com/proptest-rs/proptest/blob/main/README.md This text output demonstrates the sequence of values proptest tries during its shrinking process. It shows how the year is reduced to 0, the day to 1, and the month is explored between 12 and 6 before settling on 10, illustrating the reduction strategy. ```text y = 2497, m = 8, d = 27 y = 9641, m = 8, d = 18 y = 7360, m = 12, d = 20 y = 3680, m = 12, d = 20 y = 1840, m = 12, d = 20 y = 920, m = 12, d = 20 y = 460, m = 12, d = 20 y = 230, m = 12, d = 20 y = 115, m = 12, d = 20 y = 57, m = 12, d = 20 y = 28, m = 12, d = 20 y = 14, m = 12, d = 20 y = 7, m = 12, d = 20 y = 3, m = 12, d = 20 y = 1, m = 12, d = 20 y = 0, m = 12, d = 20 y = 0, m = 6, d = 20 y = 0, m = 9, d = 20 y = 0, m = 11, d = 20 y = 0, m = 10, d = 20 y = 0, m = 10, d = 10 y = 0, m = 10, d = 5 y = 0, m = 10, d = 3 y = 0, m = 10, d = 2 y = 0, m = 10, d = 1 ``` -------------------------------- ### Apply state transitions Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Updates the reference state based on a given transition. ```rust fn apply(mut state: Self::State, transition: &Self::Transition) -> Self::State ``` -------------------------------- ### Add proptest dependency Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Configuration for Cargo.toml to include proptest as a development dependency. ```toml [dev-dependencies] proptest = "1.10.0" ``` -------------------------------- ### Define a property-based test with proptest! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Uses the proptest! macro to test date parsing logic with integer ranges as input strategies. ```rust proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn parses_date_back_to_original(y in 0u32..10000, m in 1u32..13, d in 1u32..32) { let (y2, m2, d2) = parse_date( &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); // prop_assert_eq! is basically the same as assert_eq!, but doesn't // cause a bunch of panic messages to be printed on intermediate // test failures. Which one to use is largely a matter of taste. prop_assert_eq!((y, m, d), (y2, m2, d2)); } } ``` -------------------------------- ### Generate state transitions Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/state-machine.md Creates a strategy for generating valid transitions based on the current state. ```rust fn transitions(state: &Self::State) -> BoxedStrategy ``` -------------------------------- ### Compose Reusable Strategies with prop_compose! Source: https://context7.com/proptest-rs/proptest/llms.txt The prop_compose! macro allows creating reusable strategy-generating functions by combining multiple input strategies into complex output types. ```rust use proptest::prelude::*; #[derive(Debug, Clone, PartialEq)] struct Point { x: f64, y: f64, } #[derive(Debug, Clone)] struct Rectangle { top_left: Point, width: f64, height: f64, } prop_compose! { fn point_strategy(max_coord: f64) (x in 0.0..max_coord, y in 0.0..max_coord) -> Point { Point { x, y } } } prop_compose! { fn rectangle_strategy(max_size: f64) (top_left in point_strategy(100.0), width in 1.0..max_size, height in 1.0..max_size) -> Rectangle { Rectangle { top_left, width, height } } } proptest! { #[test] fn test_rectangle_area(rect in rectangle_strategy(50.0)) { let area = rect.width * rect.height; prop_assert!(area > 0.0); prop_assert!(area < 50.0 * 50.0); } #[test] fn test_point_in_bounds(p in point_strategy(10.0)) { prop_assert!(p.x >= 0.0 && p.x < 10.0); prop_assert!(p.y >= 0.0 && p.y < 10.0); } } ``` -------------------------------- ### E0011: Missing strategy for custom parameter Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/errors.md Specifying a parameter type requires an explicit strategy configuration to ensure type compatibility. ```rust #[derive(Debug, Arbitrary)] struct Foo { #[proptest(param = "u8")] some_string: String, } ``` -------------------------------- ### Primitive Fuzzing Test with Proptest Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/strategy-basics.md Illustrates a basic fuzzing test by repeatedly calling a function with random integer inputs generated by proptest. This approach helps identify crashes but lacks detailed input context on failure. ```rust extern crate proptest; use proptest::test_runner::TestRunner; use proptest::strategy::{Strategy, ValueTree}; fn some_function(v: i32) { // Do a bunch of stuff, but crash if v > 500 assert!(v <= 500); } #[test] fn some_function_doesnt_crash() { let mut runner = TestRunner::default(); for _ in 0..256 { let val = (0..10000i32).new_tree(&mut runner).unwrap(); some_function(val.current()); } } ``` -------------------------------- ### E0010: Conflicting parameter configuration Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/errors.md Parameters cannot be configured on both a parent item and its children simultaneously. ```rust #[derive(Debug, Arbitrary)] #[proptest(params = "String")] struct Foo { #[proptest(no_params)] bar: String, } ``` -------------------------------- ### Add Proptest Dependency Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest-derive/getting-started.md Add `proptest-derive` to your `[dev-dependencies]` in Cargo.toml. ```toml proptest-derive = "0.8.0" ``` -------------------------------- ### Recursive Strategy Generation with prop_recursive Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/recursive.md A robust implementation using the prop_recursive combinator to manage nesting depth and total node count. ```rust # extern crate proptest; use std::collections::HashMap; use proptest::prelude::*; #[derive(Clone, Debug)] enum Json { Null, Bool(bool), Number(f64), String(String), Array(Vec), Map(HashMap), } fn arb_json() -> impl Strategy { let leaf = prop_oneof![ Just(Json::Null), any::().prop_map(Json::Bool), any::().prop_map(Json::Number), ".*".prop_map(Json::String), ]; leaf.prop_recursive( 8, // 8 levels deep 256, // Shoot for maximum size of 256 nodes 10, // We put up to 10 items per collection |inner| prop_oneof![ // Take the inner strategy and make the two recursive cases. prop::collection::vec(inner.clone(), 0..10) .prop_map(Json::Array), prop::collection::hash_map(".*", inner, 0..10) .prop_map(Json::Map), ]) } ``` -------------------------------- ### Write property tests with proptest! macro Source: https://context7.com/proptest-rs/proptest/llms.txt Use the proptest! macro to define property tests that automatically generate inputs and shrink failures. The macro integrates with standard #[test] attributes. ```rust use proptest::prelude::*; fn reverse(xs: &[T]) -> Vec { xs.iter().cloned().rev().collect() } proptest! { #[test] fn test_reverse_preserves_length(ref v in prop::collection::vec(any::(), 0..100)) { prop_assert_eq!(v.len(), reverse(v).len()); } #[test] fn test_reverse_is_involutive(ref v in prop::collection::vec(any::(), 0..100)) { prop_assert_eq!(v, &reverse(&reverse(v))); } #[test] fn test_parse_roundtrip(y in 0u32..10000, m in 1u32..13, d in 1u32..32) { let date_str = format!("{:04}-{:02}-{:02}", y, m, d); // Parse and verify the date string format prop_assert!(date_str.len() == 10); prop_assert!(date_str.chars().nth(4) == Some('-')); } } ``` -------------------------------- ### State Machine Testing Source: https://context7.com/proptest-rs/proptest/llms.txt Test stateful systems by defining a reference model and a system under test. The macro generates sequences of transitions to verify invariants. ```rust use proptest::prelude::*; use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine}; // Example: Testing a simple counter struct Counter { value: i32, } #[derive(Debug, Clone)] enum Transition { Increment, Decrement, Reset, } // Reference state machine (the "model") struct CounterModel; impl ReferenceStateMachine for CounterModel { type State = i32; type Transition = Transition; fn init_state() -> BoxedStrategy { Just(0).boxed() } fn transitions(_state: &Self::State) -> BoxedStrategy { prop_oneof![ Just(Transition::Increment), Just(Transition::Decrement), Just(Transition::Reset), ].boxed() } fn apply(state: Self::State, transition: &Self::Transition) -> Self::State { match transition { Transition::Increment => state + 1, Transition::Decrement => state - 1, Transition::Reset => 0, } } } // Test implementation struct CounterTest; impl StateMachineTest for CounterTest { type SystemUnderTest = Counter; type Reference = CounterModel; fn init_test(_ref_state: &::State) -> Self::SystemUnderTest { Counter { value: 0 } } fn apply( mut state: Self::SystemUnderTest, _ref_state: &::State, transition: ::Transition, ) -> Self::SystemUnderTest { match transition { Transition::Increment => state.value += 1, Transition::Decrement => state.value -= 1, Transition::Reset => state.value = 0, } state } fn check_invariants(state: &Self::SystemUnderTest, ref_state: &::State) { assert_eq!(state.value, *ref_state, "Counter value must match model"); } } prop_state_machine! { #[test] fn test_counter_state_machine(sequential 1..50 => CounterTest); } ``` -------------------------------- ### Run Test with Parameterized Strategy Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/transforming-strategies.md Uses the `arb_order` strategy to generate an `Order` with a maximum quantity of 1000 for the `test_do_stuff` test. ```rust proptest! { #[test] fn test_do_stuff(order in arb_order(1000)) { do_stuff(order); } } ``` -------------------------------- ### Add a regression unit test Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Create a standard unit test to verify a specific failing case identified by proptest. ```rust # fn parse_date(s: &str) -> Option<(u32, u32, u32)> { # if 10 != s.len() { return None; } # # // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. # if !s.is_ascii() { return None; } # # if "-" != &s[4..5] || "-" != &s[7..8] { return None; } # # let year = &s[0..4]; # let month = &s[6..7]; # let day = &s[8..10]; # # year.parse::().ok().and_then( # |y| month.parse::().ok().and_then( # |m| day.parse::().ok().map( # |d| (y, m, d)))) # } #[test] # fn dummy() {} // Doctests don't build `#[test]` functions, so we need this fn test_october_first() { assert_eq!(Some((0, 10, 1)), parse_date("0000-10-01")); } # fn main() { test_october_first(); } ``` -------------------------------- ### Generate Collections with proptest::collection in Rust Source: https://context7.com/proptest-rs/proptest/llms.txt Utilize specialized strategies to generate vectors, hash maps, and sets with configurable size ranges. ```rust use proptest::prelude::*; use proptest::collection::{vec, hash_map, hash_set, btree_map, btree_set}; proptest! { #[test] fn test_vec_strategy( // Vec with 5-20 elements v in vec(any::(), 5..20), // Fixed size vec fixed in vec(0..100u8, 10), // Empty to some max maybe_empty in vec(".*", 0..5) ) { prop_assert!(v.len() >= 5 && v.len() < 20); prop_assert_eq!(fixed.len(), 10); prop_assert!(maybe_empty.len() < 5); } #[test] fn test_map_strategies( // HashMap with string keys and integer values hm in hash_map("[a-z]+", any::(), 1..10), // BTreeMap maintains order bm in btree_map(0..100i32, ".*", 5..15) ) { prop_assert!(hm.len() >= 1 && hm.len() < 10); prop_assert!(bm.len() >= 5 && bm.len() < 15); } #[test] fn test_set_strategies( hs in hash_set(any::(), 3..10), bs in btree_set("[a-z]{3}", 2..8) ) { prop_assert!(hs.len() >= 3); prop_assert!(bs.len() >= 2); } } ``` -------------------------------- ### Generating Vector and Valid Index with prop_compose! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/higher-order.md Utilizes the `prop_compose!` macro as a more concise way to define higher-order strategies, similar to `prop_flat_map`, for generating a vector and a corresponding valid index. ```rust # extern crate proptest; # use proptest::prelude::* prop_compose! { fn vec_and_index()(vec in prop::collection::vec(".*", 1..100)) (index in 0..vec.len(), vec in Just(vec)) -> (Vec, usize) { (vec, index) } } ``` -------------------------------- ### Configure Cargo.toml for WASM Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/wasm.md Disable default features and enable the std feature to support WASM targets. ```toml [dev-dependencies.proptest] version = "$proptestVersion" # The default feature set includes things like process forking which are not # supported in Web Assembly. default-features = false # Enable using the `std` crate. features = ["std"] ``` -------------------------------- ### Create Union Strategies with prop_oneof! in Rust Source: https://context7.com/proptest-rs/proptest/llms.txt Define strategies that randomly select from multiple alternatives, supporting both uniform and weighted probability distributions. ```rust use proptest::prelude::*; #[derive(Debug, Clone, PartialEq)] enum Value { Null, Bool(bool), Int(i64), Float(f64), String(String), } fn value_strategy() -> impl Strategy { prop_oneof![ // Each arm is weighted equally by default Just(Value::Null), any::().prop_map(Value::Bool), any::().prop_map(Value::Int), any::().prop_map(Value::Float), ".*".prop_map(Value::String), ] } fn weighted_value_strategy() -> impl Strategy { prop_oneof![ // Custom weights (higher = more likely) 1 => Just(Value::Null), 2 => any::().prop_map(Value::Bool), 5 => any::().prop_map(Value::Int), 3 => any::().prop_map(Value::Float), 4 => ".*".prop_map(Value::String), ] } proptest! { #[test] fn test_value_generation(v in value_strategy()) { // All Value variants can be generated match v { Value::Null => {} Value::Bool(_) => {} Value::Int(_) => {} Value::Float(_) => {} Value::String(_) => {} } } } ``` -------------------------------- ### Run Property-Based Tests with TestRunner Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/test-runner.md Use TestRunner to execute property-based tests, automatically handling panics and shrinking failing inputs. Configure TestRunner with custom settings like disabling failure persistence. ```rust # extern crate proptest; use proptest::test_runner::{Config, FileFailurePersistence, TestError, TestRunner}; fn some_function(v: i32) { // Do a bunch of stuff, but crash if v > 500. // We return to normal `assert!` here since `TestRunner` catches // panics. assert!(v <= 500); } // We know the function is broken, so use a purpose-built main function to // find the breaking point. fn main() { let mut runner = TestRunner::new(Config { // Turn failure persistence off for demonstration failure_persistence: Some(Box::new(FileFailurePersistence::Off)), .. Config::default() }); let result = runner.run(&(0..10000i32), |v| { some_function(v); Ok(()) }); match result { Err(TestError::Fail(_, value)) => { println!("Found minimal failing case: {}", value); assert_eq!(501, value); }, result => panic!("Unexpected result: {:?}", result), } } ``` -------------------------------- ### Define Parameterized Strategy for Order Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/transforming-strategies.md Defines a strategy for generating `Order` structs with a maximum quantity. Use `-> impl Strategy<..>` to avoid overhead unless dynamic dispatch is needed. ```rust use proptest::prelude::* #[derive(Clone, Debug)] struct Order { id: String, // Some other fields, though the test doesn't do anything with them item: String, quantity: u32, } fn arb_order(max_quantity: u32) -> impl Strategy { (any::().prop_map(|v| v.to_string()), "[a-z]*", 1..max_quantity) .prop_map(|(id, item, quantity)| Order { id, item, quantity }) } ``` -------------------------------- ### Generate String from Regex Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/transforming-strategies.md This strategy generates strings matching a regex, but it has limitations in exploring the full value space and shrinking correctly. ```rust extern crate proptest; use proptest::prelude::*; fn do_stuff(v: String) { let i: u32 = v.parse().unwrap(); let s = i.to_string(); assert_eq!(s, v); } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_do_stuff(v in "[1-9][0-9]{0,8}") { do_stuff(v); } } # fn main() { test_do_stuff(); } ``` -------------------------------- ### Generate Complex Struct using Nested prop_map Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/transforming-strategies.md Demonstrates composing strategies for a struct by nesting `prop_map` calls within a tuple strategy. ```rust extern crate proptest; use proptest::prelude::*; #[derive(Clone, Debug)] struct Order { id: String, // Some other fields, though the test doesn't do anything with them item: String, quantity: u32, } fn do_stuff(order: Order) { let i: u32 = order.id.parse().unwrap(); let s = i.to_string(); assert_eq!(s, order.id); } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_do_stuff( order in (any::().prop_map(|v| v.to_string()), "[a-z]*", 1..1000u32).prop_map( |(id, item, quantity)| Order { id, item, quantity }) ) { do_stuff(order); } } # fn main() { test_do_stuff(); } ``` -------------------------------- ### Set opt-level to 3 for Performance Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tips-and-best-practices.md To improve performance when generating many test cases, set the `opt-level` to `3` for `proptest` and `rand_chacha` in your `Cargo.toml`. ```toml [profile.test.package.proptest] opt-level = 3 [profile.test.package.rand_chacha] opt-level = 3 ``` -------------------------------- ### Apply global filters with prop_assume! Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/filtering.md Use prop_assume! to reject an entire test case when input conditions are not met, effectively triggering a global rejection. ```rust # extern crate proptest; use proptest::prelude::*; fn frob(a: i32, b: i32) -> (i32, i32) { let d = (a - b).abs(); (a / d, b / d) } proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_frob(a in -1000..1000, b in -1000..1000) { // Input illegal if a==b. // Equivalent to // if (a == b) { return Err(TestCaseError::Reject(...)); } prop_assume!(a != b); let (a2, b2) = frob(a, b); assert!(a2.abs() <= a.abs()); assert!(b2.abs() <= b.abs()); } } # fn main() { test_frob(); } ``` -------------------------------- ### Proptest Test Case with Custom Strategy Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/macro-prop-compose.md This proptest! macro defines a test case that uses the custom arb_order strategy to generate Order objects. The generated Order is then passed to the do_stuff function. ```rust proptest! { #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_do_stuff(order in arb_order(1000)) { do_stuff(order); } } ``` -------------------------------- ### Configure Proptest for `no_std` in Cargo.toml Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/no-std.md To use Proptest in a `no_std` environment, adjust your `Cargo.toml` to opt out of the `std` feature and explicitly enable `no_std`, `alloc`, and `unstable` features. This configuration is necessary for memory allocation and nightly compiler features. ```toml [dev-dependencies.proptest] version = "proptestVersion" # Opt out of the `std` feature default-features = false # alloc: Use the `alloc` crate directly. Proptest has a hard requirement on # memory allocation, so either this or `std` is needed. # unstable: Enable use of nightly-only compiler features. features = ["no_std", "alloc", "unstable"] ``` -------------------------------- ### Add regressions to git Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/getting-started.md Command to track generated failure persistence files in version control. ```text $ git add proptest-regressions ``` -------------------------------- ### Configure Proptest Test Cases with proptest_config Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/tutorial/config.md Use `#![proptest_config(ProptestConfig::with_cases(1000))]` within a `proptest!` block to set the number of test cases for that specific test. This requires the `std` feature to be enabled. ```rust # extern crate proptest; use proptest::prelude::*; fn add(a: i32, b: i32) -> i32 { a + b } proptest! { // The next line modifies the number of tests. #![proptest_config(ProptestConfig::with_cases(1000))] #[test] # fn dummy(a in 0..1) {} fn test_add(a in 0..1000i32, b in 0..1000i32) { let sum = add(a, b); assert!(sum >= a); assert!(sum >= b); } } # fn main() { # test_add(); # } ``` -------------------------------- ### Execute tests manually with TestRunner Source: https://context7.com/proptest-rs/proptest/llms.txt Use TestRunner for custom test execution, manual value generation, and deterministic testing. Requires importing TestRunner, Config, Strategy, and ValueTree. ```rust use proptest::test_runner::{TestRunner, Config}; use proptest::strategy::{Strategy, ValueTree}; fn main() { // Create a runner with default config let mut runner = TestRunner::default(); // Generate a single value let int_tree = (0..100i32).new_tree(&mut runner).unwrap(); println!("Generated: {}", int_tree.current()); // Run a test manually let result = runner.run(&(0..100i32, 0..100i32), |(a, b)| { let sum = a.checked_add(b); prop_assert!(sum.is_some(), "overflow occurred"); Ok(()) }); match result { Ok(_) => println!("All tests passed!"), Err(e) => println!("Test failed: {:?}", e), } // Deterministic runner for reproducible results let mut deterministic = TestRunner::deterministic(); let value = any::().new_tree(&mut deterministic).unwrap(); println!("Deterministic value: {}", value.current()); } #[cfg(test)] mod tests { use super::*; #[test] fn manual_shrinking() { let mut runner = TestRunner::default(); let mut tree = (0..1000i32).new_tree(&mut runner).unwrap(); println!("Initial: {}", tree.current()); // Manually shrink the value while tree.simplify() { println!("Shrunk to: {}", tree.current()); } println!("Minimal: {}", tree.current()); } } ``` -------------------------------- ### Configure test execution with ProptestConfig Source: https://context7.com/proptest-rs/proptest/llms.txt Customize test parameters like case count, timeouts, and shrink iterations using ProptestConfig within the proptest! macro block. ```rust use proptest::prelude::*; use proptest::test_runner::Config; proptest! { // Configure at the proptest! block level #![proptest_config(ProptestConfig::with_cases(1000))] #[test] fn test_with_more_cases(x in any::()) { // Runs 1000 test cases instead of default 256 prop_assert!(x.wrapping_add(1) >= 1 || x == u32::MAX); } } proptest! { #![proptest_config(ProptestConfig { cases: 500, max_shrink_iters: 10000, timeout: 60000, // 60 seconds ..ProptestConfig::default() })] #[test] fn test_with_custom_config(v in prop::collection::vec(any::(), 0..100)) { prop_assert!(v.len() < 100); } } ``` -------------------------------- ### Configure Fork and Timeout in Proptest Source: https://github.com/proptest-rs/proptest/blob/main/book/src/proptest/forking.md Use `ProptestConfig` to enable forking and set a timeout for test cases. This is useful for tests that might run indefinitely or crash. ```rust # extern crate proptest; use proptest::prelude::*; // The worst possible way to calculate Fibonacci numbers fn fib(n: u64) -> u64 { if n <= 1 { n } else { fib(n - 1) + fib(n - 2) } } proptest! { #![proptest_config(ProptestConfig { // Setting both fork and timeout is redundant since timeout implies // fork, but both are shown for clarity. fork: true, timeout: 100, # cases: 1, // Need to set this to 1 to avoid doctest running forever .. ProptestConfig::default() })] // #[test] # fn dummy(0..1) {} // Doctests don't build `#[test]` functions, so we need this fn test_fib(n: u64) { // For large n, this will variously run for an extremely long time, // overflow the stack, or panic due to integer overflow. assert!(fib(n) >= n); } } # fn main() { test_fib(); } ```