diff --git a/Cargo.toml b/Cargo.toml index 5003de6..2a96c0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,3 +95,8 @@ unwrap_used = "deny" name = "colored_diffs" path = "examples/colored_diffs.rs" required-features = ["colored"] + +[[example]] +name = "assertion_function" +path = "examples/assertion_function.rs" +required-features = ["colored"] diff --git a/examples/assertion_function.png b/examples/assertion_function.png new file mode 100644 index 0000000..a792aef Binary files /dev/null and b/examples/assertion_function.png differ diff --git a/examples/assertion_function.rs b/examples/assertion_function.rs new file mode 100644 index 0000000..fb849aa --- /dev/null +++ b/examples/assertion_function.rs @@ -0,0 +1,113 @@ +//! This example demonstrates that writing a helper function for asserting a +//! custom type is often easier than writing custom assertions. +//! +//! The helper function `assert_snake_body` is used to assert the state of a +//! snake. It reuses built-in assertions on each field. In case of failing +//! assertions, the names of the fields are printed with the failure message. +//! +//! Running the example will print a failed assertion to the console: +//! +//! ```console +//! thread 'main' (5388) panicked at examples\assertion_function.rs:64:5: +//! assertion of snake body failed: +//! +//! expected snake.length to be equal to 3 +//! but was: 2 +//! expected: 3 +//! +//! expected snake.body to contain exactly in order [Coord { x: 2, y: 1 }, Coord { x: 1, y: 1 }, Coord { x: 1, y: 2 }] +//! but was: [Coord { x: 2, y: 1 }, Coord { x: 1, y: 2 }, Coord { x: -1, y: 1 }] +//! expected: [Coord { x: 2, y: 1 }, Coord { x: 1, y: 1 }, Coord { x: 1, y: 2 }] +//! missing: [Coord { x: 1, y: 1 }] +//! extra: [Coord { x: -1, y: 1 }] +//! out-of-order: [Coord { x: 1, y: 2 }] +//! +//! expected snake.head to be equal to Coord { x: 2, y: 1 } +//! but was: Coord { x: 3, y: 1 } +//! expected: Coord { x: 2, y: 1 } +//! ``` +//! +//! [image of colored output in the console](assets/assertion_function.png) + +// just to prevent some linter warnings +mod fixture; + +use asserting::prelude::*; + +#[derive(Debug, Clone, Copy, PartialEq)] +struct Coord { + x: i32, + y: i32, +} + +struct Snake { + length: usize, + head: Coord, + body: Vec, +} + +/// Helper function for asserting a snake's state. +/// +/// It takes a snake and an expected body and asserts that the snake's +/// length, body, and head are equal to the expected body. +/// +/// It first does assertions on all fields of the snake without panicking so +/// that all found failures are printed at once and not the first one only. +/// +/// The failure messages contain names of the fields like "snake.length", +/// "snake.body" and "snake.head". +#[track_caller] +fn assert_snake_body(snake: &Snake, expected_body: &[Coord]) { + let mut failures = verify_that!(snake) + .with_configured_diff_format() + .extracting(|s| s.length) + .named("snake.length") + .is_equal_to(expected_body.len()) + .display_failures(); + failures.extend( + verify_that!(snake) + .with_configured_diff_format() + .extracting(|s| &s.body) + .named("snake.body") + .contains_exactly(expected_body) + .display_failures(), + ); + failures.extend( + verify_that!(snake) + .with_configured_diff_format() + .extracting(|s| s.head) + .named("snake.head") + .is_equal_to(expected_body[0]) + .display_failures(), + ); + assert!( + failures.is_empty(), + "assertion of snake body failed: \n\n{}", + failures.join("\n") + ); +} + +fn test() { + let snake = Snake { + length: 2, + head: Coord { x: 3, y: 1 }, + body: vec![ + Coord { x: 2, y: 1 }, + Coord { x: 1, y: 2 }, + Coord { x: -1, y: 1 }, + ], + }; + + assert_snake_body( + &snake, + &[ + Coord { x: 2, y: 1 }, + Coord { x: 1, y: 1 }, + Coord { x: 1, y: 2 }, + ], + ); +} + +fn main() { + test(); +} diff --git a/src/lib.rs b/src/lib.rs index 6094171..2fd7bad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -341,6 +341,13 @@ //! 3. Custom expectations used with the [`Spec::expecting()`] method //! 4. Custom assertions methods //! +//! > 💡 +//! > Often the easiest way to assert a custom type is to write a helper +//! > function that asserts parts (e.g., fields of a struct) using existing +//! > assertions. See the example [`assertion_function.rs`](examples/assertion_function.rs) +//! > which demonstrates how to use a helper function for asserting a custom +//! > struct. +//! //! How to use predicate functions as custom assertions is described on the //! [`Spec::satisfies()`] method and in the [Examples](#predicate-as-custom-assertion) //! chapter above. The other 3 ways are described in the following subchapters.