Skip to main content

fluent_assertions/assertions/
mod.rs

1use std::fmt::Debug;
2
3pub mod bool_assertion;
4pub mod collection_assertion;
5pub mod error_assertion;
6pub mod numeric_assertion;
7pub mod option_assertion;
8pub mod result_assertion;
9pub mod string_assertion;
10
11pub use collection_assertion::CollectionAssertion;
12pub use option_assertion::OptionAssertion;
13
14// General Should trait for all types
15pub trait Should: Sized {
16    #[must_use = "this creates an assertion but checks nothing — call an assertion method like `.be(...)`"]
17    fn should(self) -> Assertion<Self>;
18}
19
20// Implement Should for all types
21// (`#[must_use]` lives on the trait declaration above; the compiler rejects it
22// on trait methods inside impl blocks and it propagates from the declaration.)
23impl<T> Should for T {
24    fn should(self) -> Assertion<Self> {
25        Assertion { value: self }
26    }
27}
28
29// General Assertion struct
30pub struct Assertion<T> {
31    value: T,
32}
33
34impl<T> Assertion<T> {
35    /// Consumes the assertion and returns the inner value.
36    ///
37    /// This enables assert-and-continue patterns, unwrapping an inner value
38    /// after asserting on it:
39    ///
40    /// ```
41    /// use fluent_assertions::*;
42    /// let v = Some(5).should().be_some().into_inner();
43    /// assert_eq!(v, 5);
44    /// ```
45    pub fn into_inner(self) -> T {
46        self.value
47    }
48}
49
50/// General assertions for all types
51impl<T> Assertion<T>
52where
53    T: Debug,
54{
55    /// Asserts that the value equals `other`, allowing cross-type comparison.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use fluent_assertions::*;
61    /// "foo".to_string().should().be("foo");
62    /// ```
63    #[track_caller]
64    pub fn be<U: Debug>(self, other: U) -> Self
65    where
66        T: PartialEq<U>,
67    {
68        assert!(
69            self.value == other,
70            "Expected value to be {:?}, but got {:?}",
71            other,
72            self.value
73        );
74        self
75    }
76
77    /// Asserts that the value does not equal `other`.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use fluent_assertions::*;
83    /// 42.should().not_be(0);
84    /// ```
85    #[track_caller]
86    pub fn not_be<U: Debug>(self, other: U) -> Self
87    where
88        T: PartialEq<U>,
89    {
90        assert!(
91            self.value != other,
92            "Expected value to not be {:?}, but got {:?}",
93            other,
94            self.value
95        );
96        self
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use crate::assertions::*;
103
104    #[test]
105    fn be_allows_cross_type_comparison() {
106        "foo".to_string().should().be("foo");
107    }
108
109    #[test]
110    fn be_allows_debug_only_types() {
111        Some(5).should().be(Some(5));
112    }
113
114    #[test]
115    fn into_inner_returns_wrapped_value() {
116        let v = Some(5).should().be_some().into_inner();
117        assert_eq!(v, 5);
118    }
119}