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 to be 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 to have 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 to be 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>, _inverted: bool, _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>, _inverted: bool, _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>, _inverted: bool, _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>, _inverted: bool, _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.9.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 sync {
650 extern crate alloc;
651 pub use alloc::sync::*;
652 pub use core::sync::*;
653 }
654
655 pub mod ffi {
656 extern crate alloc;
657 pub use alloc::ffi::*;
658 pub use core::ffi::*;
659 }
660}
661
662#[cfg(feature = "std")]
663mod std {
664 pub use std::*;
665}
666
667pub mod assertions;
668pub mod colored;
669pub mod expectations;
670pub mod prelude;
671pub mod properties;
672pub mod spec;
673
674#[cfg(feature = "bigdecimal")]
675mod bigdecimal;
676mod boolean;
677mod c_string;
678mod char;
679mod char_count;
680mod collection;
681#[cfg(feature = "std")]
682mod env;
683mod equality;
684mod error;
685mod expectation_combinators;
686mod float;
687mod integer;
688mod iterator;
689mod length;
690mod map;
691#[cfg(feature = "num-bigint")]
692mod num_bigint;
693mod number;
694mod option;
695mod order;
696#[cfg(feature = "std")]
697mod os_sting;
698#[cfg(feature = "panic")]
699mod panic;
700mod predicate;
701mod range;
702mod result;
703#[cfg(feature = "rust-decimal")]
704mod rust_decimal;
705mod slice;
706mod string;
707mod vec;
708
709// test code snippets in the README.md
710#[cfg(doctest)]
711#[doc = include_str!("../README.md")]
712#[allow(dead_code)]
713type TestCodeSnippetsInReadme = ();
714
715// workaround for false positive 'unused extern crate' warnings until
716// Rust issue [#95513](https://github.com/rust-lang/rust/issues/95513) is fixed
717#[cfg(test)]
718mod dummy_extern_uses {
719 use fakeenv as _;
720 use proptest as _;
721 use time as _;
722 use version_sync as _;
723}