expectest/
lib.rs

1//! This project is inspired by [Nimble](https://github.com/Quick/Nimble) for Swift.
2//! It provides matchers and matcher functions to express expectations in tests for common cases,
3//! such as: Equality, Order, Option, Result, etc.
4//! The crate also provides instruments to implement custom matchers for your project's domain.
5//!
6//! You express expectations in your tests using three basic constructs:
7//!
8//! ```rust,ignore
9//! expect!(...).to(...);
10//! expect!(...).to_not(...);
11//! expect!(...).not_to(...);
12//! ```
13//!
14//! If a test fails, you will see the reason in a nice, human readable format.
15//!
16//! # Example
17//!
18//! ```rust,should_panic
19//! # use expectest::prelude::*;
20//! # fn main() {
21//! let result = vec![1, 2, 2];
22//! expect!(result).to(be_equal_to([1, 2, 3]));
23//! # }
24//! // --
25//! // This will print:
26//! // expected to be equal to <[1, 2, 3]>, got <[1, 2, 2]>
27//! ```
28//!
29//! # Structure
30//!
31//! The crate consists of two modules `core` and `matchers` but for general use
32//! you can access all you need using `prelude` module. The `expect!` macro saves
33//! file name and line number to print it later if an expectation fails. Internally the macro uses
34//! the `expect` function which is also available to you.
35//!
36//! # Usage
37//!
38//! The crate is meant to be used in tests, so we recommend you include it as a dev dependency
39//! with `#[cfg(test)]` attribute.
40//!
41//! In your Cargo.toml:
42//!
43//! ```toml
44//! [dev-dependencies]
45//! expectest = "0.10.0"
46//! ```
47//!
48//! If you prefer nightly rust and want failure messages to be integrated in rust's
49//! standard panic message, enable `nightly` feature:
50//!
51//! ```toml
52//! [dev-dependencies]
53//! expectest = { version = "0.10.0", features = ["nightly"] }
54//! ```
55//!
56//! In your tests:
57//!
58//! ```rust,ignore
59//! use expectest::prelude::*;
60//! ```
61//! # Matchers
62//!
63//! Keep in mind that some matchers work with types that implement `Debug` trait
64//! to print inner representation. You need to implement or derive it for your types.
65//!
66//! ## Equality
67//!
68//! For types that implement `PartialEq` trait you can use `be_equal_to` function or its alias
69//! `be_eq`.
70//!
71//! ```rust
72//! # use expectest::prelude::*;
73//! # fn main() {
74//! expect!("hello".to_string()).to(be_equal_to("hello"));
75//! # }
76//! ```
77//!
78//! ## Equality of Floats
79//!
80//! With default `delta` equal to `0.001`.
81//!
82//! ```rust
83//! # use expectest::prelude::*;
84//! # fn main() {
85//! expect!(12.001_f64).to(be_close_to(12.0));
86//! expect!(12.1_f64).to(be_close_to(12.0).delta(0.1));
87//! # }
88//! ```
89//!
90//! ## Order
91//!
92//! For types that implement `PartialOrd` trait you can use any of the following matchers:
93//!
94//! - `be_less_than`
95//! - `be_less_or_equal_to`
96//! - `be_greater_than`
97//! - `be_greater_or_equal_to`
98//!
99//! or their aliases respectively:
100//!
101//! - `be_lt`
102//! - `be_le`
103//! - `be_gt`
104//! - `be_ge`
105//!
106//! ```rust
107//! # use expectest::prelude::*;
108//! # fn main() {
109//! expect!(1).to(be_greater_than(0));
110//! # }
111//! ```
112//!
113//! ## Ranges
114//!
115//! For two-sided checks range matcher can be used:
116//!  - `be_within_range`
117//!
118//! ```rust
119//! # use expectest::prelude::*;
120//! # fn main() {
121//! expect!(1).to(be_within_range(0..=1));
122//! # }
123//! ```
124//!
125//! ## Option\<T\>
126//!
127//! Use `be_some` or `be_none` matchers.
128//!
129//! ```rust
130//! # use expectest::prelude::*;
131//! # fn main() {
132//! expect!(Some(9)).to(be_some());
133//! expect!(Some(9)).to(be_some().value(9));
134//! # }
135//! ```
136//!
137//! ## Result\<T, E\>
138//!
139//! Use `be_ok` or `be_err` matchers.
140//!
141//! ```rust
142//! # use expectest::prelude::*;
143//! # fn main() {
144//! expect!("4".parse::<u32>()).to(be_ok());
145//! expect!("4".parse::<u32>()).to(be_ok().value(4));
146//! # }
147//! ```
148//!
149//! ## Iterators
150//!
151//! For types that implement `Iterator + Clone` trait.
152//!
153//! Use `be_empty` or `have_count` matchers.
154//!
155//! ```rust
156//! # use expectest::prelude::*;
157//! # fn main() {
158//! expect!("".chars()).to(be_empty());
159//! expect!("abc".chars()).to(have_count(3));
160//! # }
161//! ```
162//!
163//! ## Boolean
164//!
165//! Use `be_true` or `be_false` matchers.
166//!
167//! ```rust
168//! # use expectest::prelude::*;
169//! # fn main() {
170//! expect!(9 == 9).to(be_true());
171//! # }
172//! ```
173//!
174//! That's all you need to know.
175//!
176//! **Happy Testing 😊**
177//!
178
179#![cfg_attr(feature = "nightly", feature(core_panic))]
180
181#[cfg(feature = "nightly")]
182extern crate core as rust_core;
183
184/// A macro intended to use as a powerful replacement of `expect` function.
185///
186/// Provides a file name and a line number for a failed test case.
187#[macro_export]
188macro_rules! expect {
189    ($e:expr) => {{
190        let location = $crate::core::SourceLocation::new(file!(), line!(), column!());
191        $crate::core::expect($e).location(location)
192    }};
193}
194
195pub mod prelude {
196    //! A module contains reexport of all useful functions.
197
198    pub use crate::core::expect;
199    pub use crate::expect;
200    pub use crate::matchers::{
201        be_close_to, be_empty, be_eq, be_equal_to, be_err, be_false, be_ge, be_greater_or_equal_to,
202        be_greater_than, be_gt, be_le, be_less_or_equal_to, be_less_than, be_lt, be_none, be_ok,
203        be_some, be_true, be_within_range, have_count,
204    };
205}
206
207pub mod core;
208pub mod matchers;