### Basic TestRunner Setup Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/compound-strategies.html Initial setup for a proptest test case using TestRunner. This example shows the basic structure before incorporating strategies. ```rust use proptest::test_runner::TestRunner; fn add(a: i32, b: i32) -> i32 { a + b } #[test] fn test_add() { let mut runner = TestRunner::default(); runner.run(/* uhhm... */).unwrap(); } fn main() { test_add(); } ``` -------------------------------- ### Example Output of String Shrinking Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/shrinking-basics.html These are example outputs from running the string shrinking demonstration. They illustrate how the generated strings become progressively simpler while still adhering to the initial regular expression. ```text $ target/debug/examples/tutorial-simplify-play str_val = vy꙲ꙈᴫѱΆῨῨ = y꙲ꙈᴫѱΆῨῨ = y꙲ꙈᴫѱΆῨῨ = m꙲ꙈᴫѱΆῨῨ = g꙲ꙈᴫѱΆῨῨ = d꙲ꙈᴫѱΆῨῨ = b꙲ꙈᴫѱΆῨῨ = a꙲ꙈᴫѱΆῨῨ = aꙈᴫѱΆῨῨ = aᴫѱΆῨῨ = aѱΆῨῨ = aѱΆῨῨ = aѱΆῨῨ = aиΆῨῨ = aМΆῨῨ = aЎΆῨῨ = aЇΆῨῨ = aЃΆῨῨ = aЁΆῨῨ = aЀΆῨῨ = aЀῨῨ = aЀῨ = aЀῨ = aЀῢ = aЀ῟ = aЀ῞ = aЀ῝ ``` ```text $ target/debug/examples/tutorial-simplify-play str_val = dyiꙭᾪῇΊ = yiꙭᾪῇΊ = iꙭᾪῇΊ = iꙭᾪῇΊ = iꙭᾪῇΊ = eꙭᾪῇΊ = cꙭᾪῇΊ = bꙭᾪῇΊ = aꙭᾪῇΊ = aꙖᾪῇΊ = aꙋᾪῇΊ = aꙅᾪῇΊ = aꙂᾪῇΊ = aꙁᾪῇΊ = aꙀᾪῇΊ = aꙀῇΊ = aꙀΊ = aꙀΊ = aꙀΊ = aꙀΉ = aꙀΈ ``` -------------------------------- ### Proptest Failure Output Example Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html This is an example of the output seen when a proptest fails, including the minimal failing input and the number of successful and rejected test cases. ```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. ``` -------------------------------- ### Property Test Example with `proptest!` macro Source: https://altsysrq.github.io/proptest-book/print.html Demonstrates a property test using the `proptest!` macro. This example tests the absolute value of an `i64` to ensure it's never negative. Note that edge cases like `i64::MIN` might not be found due to random sampling. ```rust use proptest::prelude::*; proptest! { #[test] fn i64_abs_is_never_negative(a: i64) { // This actually fails if a == i64::MIN, but randomly picking one // specific value out of 2⁶⁴ is overwhelmingly unlikely. assert!(a.abs() >= 0); } } ``` -------------------------------- ### Finding Boundary Conditions with Shrinking Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/shrinking-basics.html This example demonstrates how to use simplify() and complicate() to find the boundary condition of a function. It iteratively searches for the smallest input that causes a specific condition (in this case, `v <= 500`) to fail. ```rust 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"); } ``` -------------------------------- ### Generate u32 and convert to String Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html This example demonstrates an initial approach using a regex to generate strings that represent u32 values. It highlights limitations in exploring the full u32 space and shrinking behavior. ```rust 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 test_do_stuff(v in "[1-9][0-9]{0,8}") { do_stuff(v); } } fn main() { test_do_stuff(); } ``` -------------------------------- ### Proptest Intermediate Input Logging Source: https://altsysrq.github.io/proptest-book/print.html Example output from Proptest when `println!` statements are added to a test function, showing the sequence of generated inputs before a failure occurs. ```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 ``` -------------------------------- ### Demonstrate Shrinking with Strings Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/shrinking-basics.html This example shows how repeated calls to simplify() on a string strategy produce incrementally simpler outputs, both in terms of size and characters used. The shrinking process respects the strategy's defined range. ```rust 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()); } } ``` -------------------------------- ### Recursive JSON AST Generation with `prop_recursive` Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/recursive.html This example demonstrates a more robust approach to generating recursive data structures like a JSON AST using proptest's `prop_recursive` combinator. It defines a base strategy for non-recursive elements and then uses `prop_recursive` to handle nested structures within specified depth and size limits. ```rust 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), ]) } fn main() { } ``` -------------------------------- ### Property Test: Generate from Expected Output Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html A proptest setup where valid date tuples are generated, converted to strings, and then parsed back to ensure the parser correctly reconstructs the original date. ```rust proptest! { ``` -------------------------------- ### Proptest Example: i64 abs is never negative Source: https://altsysrq.github.io/proptest-book/proptest/limitations.html This test demonstrates a scenario where property testing is unlikely to find an edge case (i64::MIN). Traditional unit tests are still needed for such cases. ```rust use proptest::prelude::*; proptest! { #[test] fn i64_abs_is_never_negative(a: i64) { // This actually fails if a == i64::MIN, but randomly picking one // specific value out of 2⁶⁴ is overwhelmingly unlikely. assert!(a.abs() >= 0); } } // NOREADME fn main() { } // NOREADME ``` -------------------------------- ### Type Alias for Invalid Syntax Source: https://altsysrq.github.io/proptest-book/print.html When valid syntax is rejected for types, define a type alias. This example uses a type alias for '~str', which is not valid Rust syntax. ```rust type RetroBox = ~str; // N.B. "~str" is not valid Rust 1.30 syntax //... #[derive(Debug, Arbitrary)] #[proptest(params = "RetroBox")] struct MyStruct { /* ... */ } ``` -------------------------------- ### Constant for Invalid Value Syntax Source: https://altsysrq.github.io/proptest-book/print.html For values where the syntax is not directly supported, factor the code into a constant or function. This example defines a constant for PI_SQUARED, as Rust 1.30 does not have an exponentiation operator. ```rust // N.B. Rust 1.30 does not have an exponentiation operator. const PI_SQUARED: f64 = PI ** 2.0; //... #[derive(Debug, Arbitrary)] struct MyStruct { #[proptest(value = "PI_SQUARED")] factor: f64, } ``` -------------------------------- ### Customizing Arbitrary Parameters with `params` Source: https://altsysrq.github.io/proptest-book/proptest-derive/modifiers.html Use the `params` modifier to replace the default `Parameters` type for a struct or enum. This allows custom types like `WidgetRange` to control generation, as shown in the `any_with` example. ```rust #![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::(WidgetRange(10, 20))) { assert!(wc.desired_widget_count >= 10 && wc.desired_widget_count <= 20); } } } ``` -------------------------------- ### Struct with filter modifier (closure) Source: https://altsysrq.github.io/proptest-book/proptest-derive/modifiers.html Use the `filter` modifier with a closure to define a condition for generated values. This example filters out segments where start equals end. ```Rust #[derive(Debug, Arbitrary)] #[proptest(filter = "|segment| segment.start != segment.end")] struct NonEmptySegment { start: i32, end: i32, } ``` -------------------------------- ### Struct with generic type parameter Source: https://altsysrq.github.io/proptest-book/proptest-derive/modifiers.html By default, `#[derive(Arbitrary)]` requires generic type parameters to implement `Arbitrary`. This example shows the default behavior. ```Rust #[derive(Arbitrary)] struct MyStruct { /* ... */ } ``` ```Rust impl Arbitrary for MyStruct where T: Arbitrary { /* ... */ } ``` -------------------------------- ### Generate Random Values with Strategies Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/strategy-basics.html Demonstrates generating random i32 and string values using proptest strategies. Requires importing TestRunner, Strategy, and ValueTree. ```rust 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()); } ``` -------------------------------- ### Main function to run test_do_stuff Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html A simple main function that calls the `test_do_stuff` function, likely for manual execution or as an entry point. ```rust fn main() { test_do_stuff(); } ``` -------------------------------- ### Using prop_map to generate u32 as String Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html This snippet shows the recommended way to generate a u32 and transform it into its string representation using `prop_map`. This ensures proper shrinking in terms of the original u32. ```rust // 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 test_do_stuff(v in any::().prop_map(|v| v.to_string())) { do_stuff(v); } } fn main() { test_do_stuff(); } ``` -------------------------------- ### Using the proptest! Macro for Testing Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/macro-proptest.html This snippet demonstrates how to use the proptest! macro to define a property-based test for an 'add' function. It specifies input strategies for parameters 'a' and 'b' and includes assertions to verify the function's behavior. ```rust use proptest::prelude::*; fn add(a: i32, b: i32) -> i32 { a + b } proptest! { #[test] 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 Input Generation Trace Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html This output shows the sequence of inputs proptest generated and tested, illustrating its shrinking process from initial broad ranges to more specific values. ```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 ``` -------------------------------- ### Using prop_compose! for Higher-Order Strategies Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/higher-order.html Demonstrates the use of `prop_compose!` macro to create a higher-order strategy, which is a more concise way to achieve the same result as `prop_flat_map` for generating dependent data. ```rust 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) } } fn main() { } ``` -------------------------------- ### Proptest with Filter for Slice and Index Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/higher-order.html Demonstrates an initial attempt to test a function taking a slice and an index using a filter. This approach can lead to many rejections and infrequent generation of small data structures. ```rust fn some_function(stuff: &[String], index: usize) { /* do stuff */ } proptest! { #[test] fn test_some_function( stuff in prop::collection::vec(".*", 1..100), index in 0..100usize ) { prop_assume!(index < stuff.len()); some_function(stuff, index); } } ``` -------------------------------- ### Generating a complex struct with prop_map Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html Demonstrates how to use `prop_map` on tuples to construct a custom struct. This approach allows for composing strategies to build more complex data types. ```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 do_stuff(order: Order) { let i: u32 = order.id.parse().unwrap(); let s = i.to_string(); assert_eq!(s, order.id); } proptest! { #[test] 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(); } ``` -------------------------------- ### Testing Functions with Multiple Arguments using Tuple Strategies Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/compound-strategies.html Demonstrates how to use a tuple of strategies to generate multiple inputs for a function. The generated tuple is destructured to pass individual arguments to the function under test. ```rust use proptest::test_runner::TestRunner; fn add(a: i32, b: i32) -> i32 { a + b } #[test] 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(); } ``` -------------------------------- ### Define Order Struct and Test Function Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/macro-prop-compose.html Defines a sample `Order` struct and a test function `test_do_stuff` that utilizes custom strategies. ```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 do_stuff(order: Order) { let i: u32 = order.id.parse().unwrap(); let s = i.to_string(); assert_eq!(s, order.id); } 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 } } } proptest! { /* #[test] */ fn test_do_stuff(order in arb_order(1000)) { do_stuff(order); } } fn main() { test_do_stuff(); } ``` -------------------------------- ### Configure Proptest for no_std Source: https://altsysrq.github.io/proptest-book/proptest/no-std.html Adjust your Cargo.toml to opt out of the 'std' feature and enable 'alloc' and 'unstable' features for no_std compatibility. This requires a nightly compiler. ```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 = ["alloc", "unstable"] ``` -------------------------------- ### Adding Print Statements for Debugging Source: https://altsysrq.github.io/proptest-book/print.html Demonstrates how to insert `println!` statements within a Proptest test to observe the intermediate values of generated inputs during test execution. ```rust println!("y = {}, m = {}, d = {}", y, m, d); ``` -------------------------------- ### Run Proptest with Environment Variables Source: https://altsysrq.github.io/proptest-book/proptest/forking.html Control forking and timeouts using environment variables for `cargo test`. `PROPTEST_FORK` enables forking without a timeout, while `PROPTEST_TIMEOUT` enables forking with a specified timeout in milliseconds. ```bash # 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 ``` ```bash # Run all the proptest tests in subprocesses with a 1 second timeout. # Tests can still opt out or use a different timeout by setting `timeout: 0` # or another timeout in their own configuration. PROPTEST_TIMEOUT=1000 cargo test ``` -------------------------------- ### Run Proptest with Environment Variables Source: https://altsysrq.github.io/proptest-book/print.html Override Proptest's default configuration for forking and timeouts using environment variables. This allows for quick adjustments without modifying test code. ```bash # 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 # Run all the proptest tests in subprocesses with a 1 second timeout. # Tests can still opt out or use a different timeout by setting `timeout: 0` # or another timeout in their own configuration. PROPTEST_TIMEOUT=1000 cargo test ``` -------------------------------- ### Define Custom Order Strategy Source: https://altsysrq.github.io/proptest-book/print.html Defines a custom strategy for generating `Order` structs with a maximum quantity. Requires `proptest` crate. ```rust use proptest::prelude::* #[derive(Debug, PartialEq)] struct Order { id: String, 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 }) } ``` -------------------------------- ### Primitive Fuzzing Test with Proptest Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/strategy-basics.html Illustrates a basic fuzzing test by repeatedly generating random integers and passing them to a function that asserts a condition. This helps identify potential crashes but may not reveal boundary conditions easily. ```rust 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()); } } fn main() { } ``` -------------------------------- ### Basic Date Parsing Test with Proptest Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html This test uses integer ranges as strategies to generate year, month, and day values. It asserts that parsing a formatted date string back yields the original values. `prop_assert_eq!` is used for clearer failure messages compared to `assert_eq!`. ```rust #[test] 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)); } } ``` -------------------------------- ### Naïve Recursive JSON AST Generation (Fails) Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/recursive.html This is a naive attempt to generate a JSON Abstract Syntax Tree (AST) using recursion. It fails because `arb_json()` recurses unconditionally, leading to potential stack overflows. ```rust 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() } fn main() { } ``` -------------------------------- ### Configure Proptest with Fork and Timeout Source: https://altsysrq.github.io/proptest-book/print.html Use ProptestConfig to enable forking and set a timeout for test cases. This ensures tests run in a subprocess and are limited in execution time, helping to catch issues like infinite loops or stack overflows. ```rust 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: 1000, .. ProptestConfig::default() })] #[test] 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); } } //NOREADME fn main() { } ``` -------------------------------- ### Extracting strategy to a reusable function with BoxedStrategy Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html Shows how to extract a complex strategy into a reusable function using `boxed()`. This improves code organization and allows for parameterizing strategies. ```rust use proptest::prelude::*; // snip #[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); } fn arb_order(max_quantity: u32) -> BoxedStrategy { (any::().prop_map(|v| v.to_string()), "[a-z]*", 1..max_quantity) .prop_map(|(id, item, quantity)| Order { id, item, quantity }) .boxed() } proptest! { #[test] fn test_do_stuff(order in arb_order(1000)) { do_stuff(order); } } fn main() { test_do_stuff(); } ``` -------------------------------- ### Add proptest Dependency Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html Configuration for `Cargo.toml` to add `proptest` as a development dependency for property-based testing. ```toml [dev-dependencies] proptest = "1.0.0" ``` -------------------------------- ### Custom Order Strategy with prop_map Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html Defines a custom strategy for generating `Order` structs. It combines strategies for ID, item, and quantity, then uses `prop_map` to construct the `Order` object. ```rust 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 }) } ``` -------------------------------- ### Add Failing Case to Source Control Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html Command to add the `proptest-regressions` directory to Git version control after a property test fails. ```bash $ git add proptest-regressions ``` -------------------------------- ### Proptest Test Case for do_stuff Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html A proptest test case that uses the `arb_order` strategy to generate an `Order` and passes it to the `do_stuff` function. This demonstrates how to integrate custom strategies into tests. ```rust proptest! { #[test] fn test_do_stuff(order in arb_order(1000)) { do_stuff(order); } } ``` -------------------------------- ### Extracting strategy to a reusable function with impl Strategy Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/transforming-strategies.html An alternative to `boxed()` for extracting strategies into functions, using `-> impl Strategy`. This avoids dynamic dispatch overhead and is preferred unless dynamic dispatch is specifically needed. ```rust use proptest::prelude::*; // snip #[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(); ``` -------------------------------- ### Configure Fork and Timeout in Proptest Source: https://altsysrq.github.io/proptest-book/proptest/forking.html Use `ProptestConfig` to enable forking and set a timeout for test cases. Setting a timeout implies forking. ```rust 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: 1000, .. ProptestConfig::default() })] #[test] 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); } } ``` -------------------------------- ### Debugging Proptest Failures with Print Statements Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html To understand how proptest arrives at a failing input, insert print statements within the test function to log the generated values. This helps in tracing the shrinking process. ```rust println!("y = {}, m = {}, d = {}", y, m, d); ``` -------------------------------- ### Missing strategy for proptest(param) Source: https://altsysrq.github.io/proptest-book/proptest-derive/errors.html An error occurs if `#[proptest(params = "type")]` is set on a field without a corresponding explicit strategy defined by `#[proptest(strategy = "expr")]` or a similar modifier. Both `param` and `strategy` must be specified when configuring parameters manually. ```rust #![allow(unused)] fn main() { #[derive(Debug, Arbitrary)] struct Foo { #[proptest(param = "u8")] some_string: String, } } ``` -------------------------------- ### Unit Test for Specific Date Parsing Source: https://altsysrq.github.io/proptest-book/print.html A concrete unit test case created from a reduced failing input provided by Proptest, verifying the correct parsing of '0000-10-01'. ```rust #[test] fn test_october_first() { assert_eq!(Some((0, 10, 1)), parse_date("0000-10-01")); } ``` -------------------------------- ### Using TestRunner to Find Failing Cases Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/test-runner.html Configure and use `TestRunner` to find the minimal failing input for a function. Set `failure_persistence` to `Off` for demonstration purposes. The runner catches panics and returns `TestError::Fail` with the minimal failing value. ```rust 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), } } ``` -------------------------------- ### Configure Proptest Cases Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/config.html Use `#![proptest_config(ProptestConfig::with_cases(N))]` within a `proptest!` block to set the number of test cases to N. This overrides the default of 256. ```rust 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 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(); } ``` -------------------------------- ### Adding proptest-derive to Cargo.toml Source: https://altsysrq.github.io/proptest-book/print.html Add `proptest-derive` to the `[dev-dependencies]` section of your `Cargo.toml` file to include it in your project. ```toml proptest-derive = "0.2.0" ``` -------------------------------- ### Strategy for Simple Enum with Data Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/enums.html Define a strategy for an enum with simple and data-carrying variants using `prop_oneof!`. For variants with data, use `prop_map` to transform strategies for the data into the enum variant. ```rust use proptest::prelude::* #[derive(Debug, Clone)] enum MyEnum { SimpleCase, CaseWithSingleDatum(u32), CaseWithMultipleData(u32, String), } fn my_enum_strategy() -> impl Strategy { prop_oneof![ // For cases without data, `Just` is all you need Just(MyEnum::SimpleCase), // For cases with data, write a strategy for the interior data, then // map into the actual enum case. any::().prop_map(MyEnum::CaseWithSingleDatum), (any::(), ".*").prop_map( |(a, b)| MyEnum::CaseWithMultipleData(a, b)), ] } fn main() { } ``` -------------------------------- ### Local Filtering with prop_filter Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/filtering.html Apply a local filter to a strategy using `prop_filter`. This combinator accepts a closure that determines whether to accept or reject a generated value, along with a static string describing the rejection reason. ```rust use proptest::prelude::* proptest! { #[test] fn some_test( v in (0..1000u32) .prop_filter("Values must not divisible by 7 xor 11", |v| !((0 == v % 7) ^ (0 == v % 11))) ) { assert_eq!(0 == v % 7, 0 == v % 11); } } fn main() { some_test(); } ``` -------------------------------- ### Configure Proptest for WASM in Cargo.toml Source: https://altsysrq.github.io/proptest-book/proptest/wasm.html When compiling proptest for WASM, disable default features and enable the 'std' feature. This is necessary because some default features, like process forking, are not supported in Web Assembly. ```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"] ``` -------------------------------- ### Configure Proptest Test Cases Source: https://altsysrq.github.io/proptest-book/print.html This snippet demonstrates how to change the default number of test cases executed by proptest to 1000 using the #![proptest_config] attribute. ```rust 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 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(); } ``` -------------------------------- ### Adding proptest dependency for Rust 2015 Source: https://altsysrq.github.io/proptest-book/print.html In a Rust 2015 crate, you must add `extern crate proptest;` to the top of your crate to use proptest. ```rust #[cfg(test)] extern crate proptest; ``` -------------------------------- ### Global Filtering with prop_assume! Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/filtering.html Implement global filtering by returning `Err(TestCaseError::Reject)` from a test. The `prop_assume!` macro provides a concise way to achieve this, ensuring that the test case is regenerated if the condition is not met. ```rust use proptest::prelude::* fn frob(a: i32, b: i32) -> (i32, i32) { let d = (a - b).abs(); (a / d, b / d) } proptest! { #[test] 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 = value attribute Source: https://altsysrq.github.io/proptest-book/proptest-derive/errors.html The `#[proptest = value]` syntax is not a valid attribute form. Attributes must use the `#[proptest(key = value)]` or `#[proptest(modifier)]` format. ```rust #![allow(unused)] fn main() { #[derive(Debug, Arbitrary)] struct Foo { #[proptest = 1234] field: u8, } } ``` -------------------------------- ### Define Complex Enum Case Strategy with prop_compose! Source: https://altsysrq.github.io/proptest-book/print.html For complex enum cases, extract their strategy to a separate function using `prop_compose!`. This improves readability and maintainability of the enum strategy. ```rust use proptest::prelude::*; #[derive(Debug, Clone)] enum MyComplexEnum { SimpleCase, AnotherSimpleCase, ComplexCase { product_code: String, id: u64, chapter: String, }, } prop_compose! { fn my_complex_enum_complex_case()( product_code in "[0-9A-Z]{10,20}", id in 1u64..10000u64, chapter in "X{0,2}(V?I{1,3}|IV|IX)", ) -> MyComplexEnum { MyComplexEnum::ComplexCase { product_code, id, chapter } } } fn my_enum_strategy() -> BoxedStrategy { prop_oneof![ Just(MyComplexEnum::SimpleCase), Just(MyComplexEnum::AnotherSimpleCase), my_complex_enum_complex_case(), ].boxed() } fn main() { } ``` -------------------------------- ### Add proptest-derive to Cargo.toml Source: https://altsysrq.github.io/proptest-book/proptest-derive/getting-started.html Add proptest-derive to your dev-dependencies in Cargo.toml. For Rust 2015 crates, also add `extern crate proptest;` to the crate root. ```toml proptest-derive = "0.2.0" ``` ```rust #[cfg(test)] extern crate proptest; ``` -------------------------------- ### Proptest: Ensure Date Parser Does Not Crash Source: https://altsysrq.github.io/proptest-book/print.html A property test using proptest to ensure the `parse_date` function does not panic or crash when given arbitrary non-control character strings. ```rust // Bring the macros and other important things into scope. use proptest::prelude::*; proptest! { #[test] fn doesnt_crash(s in "\\PC*") { parse_date(&s); } } ``` -------------------------------- ### Adding Failing Test Case to Regression File Source: https://altsysrq.github.io/proptest-book/proptest/getting-started.html After identifying a failing input, add it to a regression file to ensure it's caught by future test runs. This is done by staging the file using `git add`. ```bash $ git add proptest-regressions ``` -------------------------------- ### Generate Even Integers with prop_compose Source: https://altsysrq.github.io/proptest-book/proptest/tutorial/filtering.html Use `prop_compose` to transform a base integer into an even integer within a specified range. This is an alternative to filtering when a direct mapping is possible. ```rust use proptest::prelude::* prop_compose! { // Generate arbitrary integers up to half the maximum desired value, // then multiply them by 2, thus producing only even integers in the // desired range. fn even_integer(max: i32)(base in 0..max/2) -> i32 { base * 2 } } fn main() { } ```