asserting/
lib.rs

1//! Fluent assertions for tests in Rust that are convenient to write and easy
2//! to extend.
3//!
4//! Fluent assertions have some significant advantages - in general and
5//! particularly as provided by this crate:
6//!
7//! * express the intent of an assertion
8//! * an assertion reads more like natural english
9//! * concise and expressive assertions for more complex types like collections
10//! * distinct and more helpful error messages for specific assertions
11//! * easy spotting the difference between the expected and the actual value
12//! * chaining of multiple assertions on the same subject
13//! * soft assertions
14//!
15//! An additional benefit of `asserting` is that it highlights differences
16//! between the expected value and the actual value for failed assertions.
17//! See the documentation of the [`colored`] module for more information on
18//! "colored diffs".
19//!
20//! # Usage
21//!
22//! To write fluent assertions in tests, import this crate's `prelude`
23//! module in your test module, like so:
24//!
25//! ```
26//! use asserting::prelude::*;
27//! ```
28//!
29//! Importing the `prelude` module is the intended way to use this crate. The
30//! prelude re-exports all types, traits and functions and macros that are
31//! needed to write assertions in tests.
32//!
33//! Start writing assertion by applying the [`assert_that!`] macro to the subject
34//! to be asserted. Then call an assertion
35//! function like `is_equal_to`, like so:
36//!
37//! ```
38//! # use asserting::prelude::*;
39//! let some_result = 7 * 6;
40//! assert_that!(some_result).is_equal_to(42);
41//! ```
42//!
43//! The subject can be any expression, e.g.:
44//!
45//! ```
46//! # use asserting::prelude::*;
47//! assert_that!(6 * 8 - 6).is_equal_to(42);
48//! ```
49//!
50//! The variable or expression inside the call of the [`assert_that!`] macro is
51//! repeated in the error message when an assertion fails. For example, the
52//! assertion:
53//!
54//! ```no_run
55//! # use asserting::prelude::*;
56//! assert_that!(6 * 8 - 5).is_equal_to(42);
57//! ```
58//!
59//! will print the error message:
60//!
61//! ```console
62//! assertion failed: expected 6 * 8 - 5 is equal to 42
63//!    but was: 43
64//!   expected: 42
65//! ```
66//!
67//! By default, the differences between the expected value and the actual value
68//! are highlighted using colors. See the [`colored`] module for more
69//! information on "colored diffs".
70//!
71//! # Examples
72//!
73//! ## Basic assertions
74//!
75//! ```
76//! use asserting::prelude::*;
77//!
78//! assert_that!(3 + 5).is_equal_to(8);
79//! assert_that!(69).is_not_equal_to(42);
80//!
81//! assert_that!(5).is_greater_than(3);
82//! assert_that!(42).is_at_most(99);
83//!
84//! assert_that!(-0.57).is_in_range(-1.0..=1.0);
85//! assert_that!('M').is_in_range('A'..='Z');
86//! assert_that!('M').is_not_in_range('a'..='z');
87//!
88//! let subject = "anim proident eiusmod sint".to_string();
89//! assert_that!(subject).contains("eiusmod");
90//!
91//! let subject = Some("consectetur veniam at nulla".to_string());
92//! assert_that!(subject).has_value("consectetur veniam at nulla");
93//!
94//! let subject: Result<i8, String> = Ok(42);
95//! assert_that!(subject).has_value(42);
96//!
97//! let subject: Option<f64> = None;
98//! assert_that!(subject).is_none();
99//!
100//! let subject: Result<(), String> = Err("labore qui eu illum".to_string());
101//! assert_that!(subject).has_error("labore qui eu illum");
102//!
103//! let subject = vec![1, 3, 5, 7, 9, 11];
104//! assert_that!(subject).contains_exactly([1, 3, 5, 7, 9, 11]);
105//! ```
106//!
107//! ## Chaining assertions on the same subject
108//!
109//! ```
110//! use asserting::prelude::*;
111//!
112//! assert_that!("commodo nobis cum duis")
113//!     .starts_with("commodo")
114//!     .ends_with(" duis")
115//!     .has_length(22);
116//!
117//! assert_that!(vec![1, 19, 1, 29, 5, 5, 7, 23, 17, 11, 3, 23, 13, 1])
118//!     .contains_all_of([1, 11, 13, 17, 19])
119//!     .contains_only([1, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31, 37, 43]);
120//! ```
121//!
122//! ## Asserting each item of a collection or iterator
123//!
124//! ```
125//! use asserting::prelude::*;
126//!
127//! let numbers = [2, 4, 6, 8, 10];
128//!
129//! assert_that!(numbers).each_item(|e|
130//!     e.is_greater_than(1)
131//!         .is_at_most(10)
132//! );
133//! ```
134//!
135//! For more details see [`Spec::each_item()`].
136//!
137//! ## Soft assertions
138//!
139//! ```should_panic
140//! use asserting::prelude::*;
141//!
142//! verify_that!("the answer to all important questions is 42")
143//!     .contains("unimportant")
144//!     .has_at_most_length(41)
145//!     .soft_panic();
146//! ```
147//!
148//! executes both assertions and prints the messages of both failing
149//! assertions in the panic message:
150//!
151//! ```console
152//! assertion failed: expected subject to contain "unimportant"
153//!    but was: "the answer to all important questions is 42"
154//!   expected: "unimportant"
155//!
156//! assertion failed: expected subject has at most a length of 41
157//!    but was: 43
158//!   expected: <= 41
159//! ```
160//!
161//! For more details see [`Spec::soft_panic()`].
162//!
163//! ## Asserting custom types
164//!
165//! We can extract a property of a custom type and assert its value:
166//!
167//! ```
168//! # use asserting::prelude::*;
169//! struct MyStruct {
170//!     important_property: String,
171//!     other_property: f64,
172//! }
173//!
174//! let some_thing = MyStruct {
175//!     important_property: "imperdiet aliqua zzril eiusmod".into(),
176//!     other_property: 99.9,
177//! };
178//!
179//! assert_that!(some_thing).extracting(|s| s.important_property)
180//!     .is_equal_to("imperdiet aliqua zzril eiusmod");
181//!
182//! ```
183//!
184//! Or we can map a custom type that does not implement a required trait to some
185//! supported type, e.g., a tuple in this example:
186//!
187//! ```
188//! # use asserting::prelude::*;
189//! struct Point {
190//!     x: i64,
191//!     y: i64,
192//! }
193//!
194//! let target = Point { x: 12, y: -64 };
195//!
196//! assert_that!(target).mapping(|s| (s.x, s.y)).is_equal_to((12, -64));
197//! ```
198//!
199//! ## Predicate as custom assertion
200//!
201//! We can use any predicate function for a custom assertion:
202//!
203//! ```
204//! # use asserting::prelude::*;
205//! fn is_odd(value: &i32) -> bool {
206//!     value & 1 == 1
207//! }
208//!
209//! assert_that!(37).satisfies_with_message("expected my number to be odd", is_odd);
210//! ```
211//!
212//! ## Assert that some code panics or does not panic
213//!
214//! Requires crate feature `panic`.
215//!
216//! ```
217//! # #[cfg(not(feature = "panic"))]
218//! # fn main() {}
219//! # #[cfg(feature = "panic")]
220//! # fn main() {
221//! use asserting::prelude::*;
222//!
223//! fn divide(a: i32, b: i32) -> i32 {
224//!     a / b
225//! }
226//!
227//! assert_that_code!(|| { divide(7, 0); }).panics();
228//!
229//! assert_that_code!(|| { divide(7, 0); })
230//!     .panics_with_message("attempt to divide by zero");
231//!
232//! assert_that_code!(|| { divide(7, 3); }).does_not_panic();
233//! # }
234//! ```
235//!
236//! # The `assert_that` and `verify_that` functions and macros
237//!
238//! Assertions can be written in two ways. The standard way that panics when
239//! an assertion fails or the alternative way that collects failures from
240//! failed assertions which can be read later.
241//!
242//! To call assertion functions on a subject, it is wrapped into the [`Spec`]
243//! struct. This can be done by calling one of the functions:
244//!
245//! * [`assert_that`] - wraps the subject into a [`Spec`] that panics if an
246//!   assertion fails
247//! * [`verify_that`] - wraps the subject into a [`Spec`] that collects failures
248//!   from assertions, which can be read later.
249//! * [`assert_that_code`] - wraps a closure into a [`Spec`] for asserting
250//!   whether the code in the closure panics or does not panic. It panics if an
251//!   assertion fails.
252//! * [`verify_that_code`] - wraps a closure into a [`Spec`] for asserting
253//!   whether the code in the closure panics or does not panic. It collects
254//!   failures from assertions, which can be read later.
255//!
256//! The [`Spec`] can hold additional information about the subject, such as the
257//! expression we are asserting, the code location of the assert statement and
258//! an optional description of what we are going to assert. These attributes are
259//! all optional and must be set explicitly by the user.
260//!
261//! For convenience, a set of macros with the same names as the functions above
262//! is provided which set the expression and the code location for the user.
263//!
264//! * [`assert_that!`] - calls the [`assert_that`] function and sets the
265//!   expression inside the macro call as the expression in the [`Spec`] as well
266//!   as the location of the macro call as the code location.
267//! * [`verify_that!`] - calls the [`verify_that`] function and sets the
268//!   expression inside the macro call as the expression in the [`Spec`] as well
269//!   as the location of the macro call as the code location.
270//! * [`assert_that_code!`] - calls the [`assert_that_code`] function and sets
271//!   the expression inside the macro call as the expression in the [`Spec`] as
272//!   well as the location of the macro call as the code location.
273//! * [`verify_that_code!`] - calls the [`verify_that_code`] function and sets
274//!   the expression inside the macro call as the expression in the [`Spec`] as
275//!   well as the location of the macro call as the code location.
276//!
277//! For example, calling the macro [`assert_that!`] like so:
278//!
279//! ```
280//! # use asserting::prelude::*;
281//! assert_that!(7 * 6).is_equal_to(42);
282//! ```
283//!
284//! is equivalent to calling the function [`assert_that`] and then calling
285//! the methods [`named()`] and [`located_at()`] on the returned [`Spec`],
286//! like so:
287//!
288//! ```
289//! # use asserting::prelude::*;
290//! assert_that(7 * 6)
291//!     .named("7 * 6")
292//!     .located_at(
293//!         Location {
294//!             file: file!(),
295//!             line: line!(),
296//!             column: column!(),
297//!         }
298//!     ).is_equal_to(42);
299//! ```
300//!
301//! When using the `verfiy_*` variants of the macros or functions for each
302//! failing assertion, a failure of type [`AssertFailure`] is added to the
303//! [`Spec`]. We can read the failures collected by calling the [`failures()`]
304//! method, like so:
305//!
306//! ```
307//! # use asserting::prelude::*;
308//! let failures = verify_that!(7 * 5).is_equal_to(42).failures();
309//!
310//! assert_that!(failures).has_length(1);
311//! ```
312//!
313//! or to get a list of formatted failure messages, we can call the
314//! [`display_failures()`] method, like so:
315//!
316//! ```
317//! # use asserting::prelude::*;
318//!
319//! let failures = verify_that!(7 * 5).is_equal_to(42).display_failures();
320//!
321//! assert_that!(failures).contains_exactly([
322//!     r"assertion failed: expected 7 * 5 is equal to 42
323//!    but was: 35
324//!   expected: 42
325//! "
326//! ]);
327//! ```
328//!
329//! # Custom assertions
330//!
331//! `asserting` provides 4 ways to do custom assertions:
332//!
333//! 1. Predicate functions as custom assertions used with the [`Spec::satisfies()`] method
334//! 2. Property base assertions for any type that implements a property trait
335//! 3. Custom expectations used with the [`Spec::expecting()`] method
336//! 4. Custom assertions methods
337//!
338//! How to use predicate functions as custom assertions is described on the
339//! [`Spec::satisfies()`] method and in the [Examples](#predicate-as-custom-assertion)
340//! chapter above. The other 3 ways are described in the following subchapters.
341//!
342//! ## Property-based assertions
343//!
344//! Some assertions provided by `asserting` are so-called property-based
345//! assertions. They are implemented for all types that implement a related
346//! property trait.
347//!
348//! For example, the `has_length()` assertion is implemented for all types that
349//! implement the [`LengthProperty`].
350//!
351//! If we want to provide the `has_length()` assertion for a custom type, we
352//! simply need to implement the [`LengthProperty`] trait for this type.
353//!
354//! Let's assume we have a custom struct `PathWay` and we implement the
355//! [`LengthProperty`] for `PathWay`:
356//!
357//! ```
358//! use asserting::properties::LengthProperty;
359//!
360//! #[derive(Debug)]
361//! struct PathWay {
362//!     len: usize
363//! }
364//!
365//! impl LengthProperty for PathWay {
366//!     fn length_property(&self) -> usize {
367//!         self.len
368//!     }
369//! }
370//! ```
371//!
372//! Then we can assert the length of a `PathWay` using the `has_length()`
373//! assertion:
374//!
375//! ```
376//! # use asserting::properties::LengthProperty;
377//! #
378//! # #[derive(Debug)]
379//! # struct PathWay {
380//! #    len: usize
381//! # }
382//! #
383//! # impl LengthProperty for PathWay {
384//! #     fn length_property(&self) -> usize {
385//! #         self.len
386//! #     }
387//! # }
388//! use asserting::prelude::*;
389//!
390//! let some_path = PathWay { len: 27 };
391//!
392//! assert_that!(some_path).has_length(27);
393//! ```
394//!
395//! Browse the [`properties`] module to see which property traits are available.
396//!
397//! ## Writing custom expectations
398//!
399//! A custom expectation is any type that implements the [`Expectation`] trait.
400//! For example, let's assume we have a custom type `Either` and want to write
401//! an expectation that verifies that a value of type `Either` is a left value.
402//!
403//! ```no_run
404//! use asserting::spec::{DiffFormat, Expectation, Expression, Unknown};
405//! use std::fmt::Debug;
406//!
407//! #[derive(Debug)]
408//! enum Either<L, R> {
409//!     Left(L),
410//!     Right(R),
411//! }
412//!
413//! struct IsLeft;
414//!
415//! impl<L, R> Expectation<Either<L, R>> for IsLeft
416//! where
417//!     L: Debug,
418//!     R: Debug,
419//! {
420//!     fn test(&mut self, subject: &Either<L, R>) -> bool {
421//!         match subject {
422//!             Either::Left(_) => true,
423//!             _ => false,
424//!         }
425//!     }
426//!
427//!     fn message(&self, expression: &Expression<'_>, actual: &Either<L, R>, _format: &DiffFormat) -> String {
428//!         format!(
429//!             "expected {expression} is {:?}\n   but was: {actual:?}\n  expected: {:?}",
430//!             Either::Left::<_, Unknown>(Unknown),
431//!             Either::Left::<_, Unknown>(Unknown),
432//!         )
433//!      }
434//! }
435//! ```
436//!
437//! We can now use the expectation `IsLeft` with the [`Spec::expecting()`]
438//! method:
439//!
440//! ```
441//! # use asserting::spec::{DiffFormat, Expectation, Expression, Unknown};
442//! # use std::fmt::Debug;
443//! #
444//! # #[derive(Debug)]
445//! # enum Either<L, R> {
446//! #     Left(L),
447//! #     Right(R),
448//! # }
449//! #
450//! # struct IsLeft;
451//! #
452//! # impl<L, R> Expectation<Either<L, R>> for IsLeft
453//! # where
454//! #     L: Debug,
455//! #     R: Debug,
456//! # {
457//! #     fn test(&mut self, subject: &Either<L, R>) -> bool {
458//! #         match subject {
459//! #             Either::Left(_) => true,
460//! #             _ => false,
461//! #         }
462//! #     }
463//! #
464//! #     fn message(&self, expression: &Expression<'_>, actual: &Either<L, R>, _format: &DiffFormat) -> String {
465//! #         format!(
466//! #             "expected {expression} is {:?}\n   but was: {actual:?}\n  expected: {:?}",
467//! #             Either::Left::<_, Unknown>(Unknown),
468//! #             Either::Left::<_, Unknown>(Unknown),
469//! #         )
470//! #      }
471//! # }
472//! use asserting::prelude::*;
473//!
474//! let subject: Either<String, i64> = Either::Left("left value".to_string());
475//!
476//! assert_that!(subject).expecting(IsLeft);
477//! ```
478//!
479//! ## Providing a custom assertion method
480//!
481//! In the previous chapter, we implemented a custom expectation which can be
482//! used with the [`Spec::expecting()`] method. But this way is not very
483//! expressive.
484//!
485//! Additionally, we can implement a custom assertion method via an extension
486//! trait.
487//!
488//! ```
489//! # use asserting::spec::{DiffFormat, Expectation, Expression, Unknown};
490//! #
491//! # #[derive(Debug)]
492//! # enum Either<L, R> {
493//! #     Left(L),
494//! #     Right(R),
495//! # }
496//! #
497//! # struct IsLeft;
498//! #
499//! # impl<L, R> Expectation<Either<L, R>> for IsLeft
500//! # where
501//! #     L: Debug,
502//! #     R: Debug,
503//! # {
504//! #     fn test(&mut self, subject: &Either<L, R>) -> bool {
505//! #         match subject {
506//! #             Either::Left(_) => true,
507//! #             _ => false,
508//! #         }
509//! #     }
510//! #
511//! #     fn message(&self, expression: &Expression<'_>, actual: &Either<L, R>, _format: &DiffFormat) -> String {
512//! #         format!(
513//! #             "expected {expression} is {:?}\n   but was: {actual:?}\n  expected: {:?}",
514//! #             Either::Left::<_, Unknown>(Unknown),
515//! #             Either::Left::<_, Unknown>(Unknown),
516//! #         )
517//! #      }
518//! # }
519//! use asserting::spec::{FailingStrategy, Spec};
520//! use std::fmt::Debug;
521//!
522//! pub trait AssertEither {
523//!     fn is_left(self) -> Self;
524//! }
525//!
526//! impl<L, R, Q> AssertEither for Spec<'_, Either<L, R>, Q>
527//! where
528//!     L: Debug,
529//!     R: Debug,
530//!     Q: FailingStrategy,
531//! {
532//!     fn is_left(self) -> Self {
533//!         self.expecting(IsLeft)
534//!     }
535//! }
536//! ```
537//!
538//! Now we can use the assertion method `is_left()` for asserting whether a
539//! subject of type `Either` is a left value.
540//!
541//! ```
542//! # use asserting::spec::{DiffFormat, Expectation, Expression, Unknown};
543//! # use std::fmt::Debug;
544//! #
545//! # #[derive(Debug)]
546//! # enum Either<L, R> {
547//! #     Left(L),
548//! #     Right(R),
549//! # }
550//! #
551//! # struct IsLeft;
552//! #
553//! # impl<L, R> Expectation<Either<L, R>> for IsLeft
554//! # where
555//! #     L: Debug,
556//! #     R: Debug,
557//! # {
558//! #     fn test(&mut self, subject: &Either<L, R>) -> bool {
559//! #         match subject {
560//! #             Either::Left(_) => true,
561//! #             _ => false,
562//! #         }
563//! #     }
564//! #
565//! #     fn message(&self, expression: &Expression<'_>, actual: &Either<L, R>, _format: &DiffFormat) -> String {
566//! #         format!(
567//! #             "expected {expression} is {:?}\n   but was: {actual:?}\n  expected: {:?}",
568//! #             Either::Left::<_, Unknown>(Unknown),
569//! #             Either::Left::<_, Unknown>(Unknown),
570//! #         )
571//! #      }
572//! # }
573//! # use asserting::spec::{FailingStrategy, Spec};
574//! #
575//! # pub trait AssertEither {
576//! #     fn is_left(self) -> Self;
577//! # }
578//! #
579//! # impl<L, R, Q> AssertEither for Spec<'_, Either<L, R>, Q>
580//! # where
581//! #     L: Debug,
582//! #     R: Debug,
583//! #     Q: FailingStrategy,
584//! # {
585//! #     fn is_left(self) -> Self {
586//! #         self.expecting(IsLeft)
587//! #     }
588//! # }
589//! use asserting::prelude::*;
590//!
591//! let subject: Either<String, i64> = Either::Left("left value".to_string());
592//!
593//! assert_that!(subject).is_left();
594//! ```
595//!
596//! [`AssertFailure`]: spec::AssertFailure
597//! [`Expectation`]: spec::Expectation
598//! [`LengthProperty`]: properties::LengthProperty
599//! [`Spec`]: spec::Spec
600//! [`Spec::each_item()`]: spec::Spec::each_item
601//! [`Spec::expecting()`]: spec::Spec::expecting
602//! [`Spec::satisfies()`]: spec::Spec::satisfies
603//! [`Spec::soft_panic()`]: spec::Spec::soft_panic
604//! [`assert_that`]: spec::assert_that
605//! [`assert_that_code`]: spec::assert_that_code
606//! [`verify_that`]: spec::verify_that
607//! [`verify_that_code`]: spec::verify_that_code
608//! [`display_failures()`]: spec::Spec::display_failures
609//! [`failures()`]: spec::Spec::failures
610//! [`named()`]: spec::Spec::named
611//! [`located_at()`]: spec::Spec::located_at
612
613#![doc(html_root_url = "https://docs.rs/asserting/0.7.0")]
614#![cfg_attr(not(feature = "std"), no_std)]
615// Render feature requirements in docs.rs
616#![cfg_attr(docsrs, feature(doc_cfg))]
617
618#[cfg(not(feature = "std"))]
619#[allow(unused_imports)]
620mod std {
621    extern crate alloc;
622    pub use alloc::*;
623    pub use core::*;
624
625    pub mod borrow {
626        extern crate alloc;
627        pub use alloc::borrow::*;
628        pub use core::borrow::*;
629    }
630
631    pub mod fmt {
632        extern crate alloc;
633        pub use alloc::fmt::*;
634        pub use core::fmt::*;
635    }
636
637    pub mod slice {
638        extern crate alloc;
639        pub use alloc::slice::*;
640        pub use core::slice::*;
641    }
642
643    pub mod str {
644        extern crate alloc;
645        pub use alloc::str::*;
646        pub use core::str::*;
647    }
648
649    pub mod ffi {
650        extern crate alloc;
651        pub use alloc::ffi::*;
652        pub use core::ffi::*;
653    }
654}
655
656#[cfg(feature = "std")]
657mod std {
658    pub use std::*;
659}
660
661pub mod assertions;
662pub mod colored;
663pub mod expectations;
664pub mod prelude;
665pub mod properties;
666pub mod spec;
667
668mod boolean;
669mod c_string;
670mod char_count;
671mod collection;
672mod equality;
673mod error;
674mod float;
675mod integer;
676mod iterator;
677mod length;
678mod map;
679mod number;
680mod option;
681mod order;
682#[cfg(feature = "std")]
683mod os_sting;
684mod predicate;
685mod range;
686mod result;
687mod slice;
688mod string;
689mod vec;
690
691#[cfg(feature = "panic")]
692mod panic;
693
694// test code snippets in the README.md
695#[cfg(doctest)]
696#[doc = include_str!("../README.md")]
697#[allow(dead_code)]
698type TestCodeSnippetsInReadme = ();
699
700// workaround for false positive 'unused extern crate' warnings until
701// Rust issue [#95513](https://github.com/rust-lang/rust/issues/95513) is fixed
702#[cfg(test)]
703mod dummy_extern_uses {
704    use proptest as _;
705    use serial_test as _;
706    use time as _;
707    use version_sync as _;
708}