assertables/assert_ends_with/
assert_ends_with.rs

1//! Assert an expression (such as a string) ends with an expression (such as a string).
2//!
3//! Pseudocode:<br>
4//! a.ends_with(b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! // String ends with substring?
12//! let sequence: &str = "alfa";
13//! let subsequence: &str = "fa";
14//! assert_ends_with!(sequence, subsequence);
15//!
16//! // Vector ends with element?
17//! let sequence = vec![1, 2, 3];
18//! let subsequence = [3];
19//! assert_ends_with!(sequence, subsequence);
20//! ```
21//!
22//! # Module macros
23//!
24//! * [`assert_ends_with`](macro@crate::assert_ends_with)
25//! * [`assert_ends_with_as_result`](macro@crate::assert_ends_with_as_result)
26//! * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
27
28/// Assert an expression (such as a string) ends with an expression (such as a substring).
29///
30/// Pseudocode:<br>
31/// a.ends_with(b)
32///
33/// * If true, return Result `Ok(())`.
34///
35/// * Otherwise, return Result `Err(message)`.
36///
37/// This macro is useful for runtime checks, such as checking parameters,
38/// or sanitizing inputs, or handling different results in different ways.
39///
40/// # Module macros
41///
42/// * [`assert_ends_with`](macro@crate::assert_ends_with)
43/// * [`assert_ends_with_as_result`](macro@crate::assert_ends_with_as_result)
44/// * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
45///
46#[macro_export]
47macro_rules! assert_ends_with_as_result {
48    ($sequence:expr, $subsequence:expr $(,)?) => {
49        match (&$sequence, &$subsequence) {
50            (sequence, subsequence) => {
51                if sequence.ends_with(subsequence) {
52                    Ok(())
53                } else {
54                    Err(format!(
55                        concat!(
56                            "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
57                            "https://docs.rs/assertables/",
58                            env!("CARGO_PKG_VERSION"),
59                            "/assertables/macro.assert_ends_with.html\n",
60                            "     sequence label: `{}`,\n",
61                            "     sequence debug: `{:?}`,\n",
62                            "  subsequence label: `{}`,\n",
63                            "  subsequence debug: `{:?}`",
64                        ),
65                        stringify!($sequence),
66                        sequence,
67                        stringify!($subsequence),
68                        subsequence,
69                    ))
70                }
71            }
72        }
73    };
74}
75
76#[cfg(test)]
77mod test_assert_ends_with_as_result {
78    use std::sync::Once;
79
80    #[test]
81    fn success() {
82        let sequence = "alfa";
83        let subsequence = "fa";
84        for _ in 0..1 {
85            let actual = assert_ends_with_as_result!(sequence, subsequence);
86            assert_eq!(actual.unwrap(), ());
87        }
88    }
89
90    #[test]
91    fn success_once() {
92        static A: Once = Once::new();
93        fn a() -> &'static str {
94            if A.is_completed() {
95                panic!("A.is_completed()")
96            } else {
97                A.call_once(|| {})
98            }
99            "alfa"
100        }
101
102        static B: Once = Once::new();
103        fn b() -> &'static str {
104            if B.is_completed() {
105                panic!("B.is_completed()")
106            } else {
107                B.call_once(|| {})
108            }
109            "fa"
110        }
111
112        assert_eq!(A.is_completed(), false);
113        assert_eq!(B.is_completed(), false);
114        let result = assert_ends_with_as_result!(a(), b());
115        assert!(result.is_ok());
116        assert_eq!(A.is_completed(), true);
117        assert_eq!(B.is_completed(), true);
118    }
119
120    #[test]
121    fn failure() {
122        let sequence = "alfa";
123        let subsequence = "al";
124        let actual = assert_ends_with_as_result!(sequence, subsequence);
125        let message = concat!(
126            "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
127            "https://docs.rs/assertables/",
128            env!("CARGO_PKG_VERSION"),
129            "/assertables/macro.assert_ends_with.html\n",
130            "     sequence label: `sequence`,\n",
131            "     sequence debug: `\"alfa\"`,\n",
132            "  subsequence label: `subsequence`,\n",
133            "  subsequence debug: `\"al\"`"
134        );
135        assert_eq!(actual.unwrap_err(), message);
136    }
137}
138
139/// Assert an expression (such as a string) ends with an expression (such as a string).
140///
141/// Pseudocode:<br>
142/// a.ends_with(b)
143///
144/// * If true, return `()`.
145///
146/// * Otherwise, call [`panic!`] with a message and the values of the
147///   expressions with their debug representations.
148///
149/// # Examples
150///
151/// ```rust
152/// use assertables::*;
153/// # use std::panic;
154///
155/// # fn main() {
156/// // String ends with substring?
157/// let sequence: &str = "alfa";
158/// let subsequence: &str = "fa";
159/// assert_ends_with!(sequence, subsequence);
160///
161/// // Vector ends with element?
162/// let sequence = vec![1, 2, 3];
163/// let subsequence = [3];
164/// assert_ends_with!(sequence, subsequence);
165///
166/// # let result = panic::catch_unwind(|| {
167/// // This will panic
168/// let sequence = "alfa";
169/// let subsequence = "al";
170/// assert_ends_with!(sequence, subsequence);
171/// # });
172/// // assertion failed: `assert_ends_with!(sequence, subsequence)`
173/// // https://docs.rs/assertables/9.7.0/assertables/macro.assert_ends_with.html
174/// //  sequence label: `sequence`,
175/// //  sequence debug: `\"alfa\"`,
176/// //   part label: `subsequence`,
177/// //   part debug: `\"al\"`
178/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
179/// # let message = concat!(
180/// #     "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
181/// #     "https://docs.rs/assertables/", env!("CARGO_PKG_VERSION"), "/assertables/macro.assert_ends_with.html\n",
182/// #     "     sequence label: `sequence`,\n",
183/// #     "     sequence debug: `\"alfa\"`,\n",
184/// #     "  subsequence label: `subsequence`,\n",
185/// #     "  subsequence debug: `\"al\"`"
186/// # );
187/// # assert_eq!(actual, message);
188/// # }
189/// ```
190///
191/// # Module macros
192///
193/// * [`assert_ends_with`](macro@crate::assert_ends_with)
194/// * [`assert_ends_with_as_result`](macro@crate::assert_ends_with_as_result)
195/// * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
196///
197#[macro_export]
198macro_rules! assert_ends_with {
199    ($sequence:expr, $subsequence:expr $(,)?) => {
200        match $crate::assert_ends_with_as_result!($sequence, $subsequence) {
201            Ok(()) => (),
202            Err(err) => panic!("{}", err),
203        }
204    };
205    ($sequence:expr, $subsequence:expr, $($message:tt)+) => {
206        match $crate::assert_ends_with_as_result!($sequence, $subsequence) {
207            Ok(()) => (),
208            Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
209        }
210    };
211}
212
213#[cfg(test)]
214mod test_assert_ends_with {
215    use std::panic;
216
217    #[test]
218    fn success() {
219        let sequence = "alfa";
220        let subsequence = "fa";
221        for _ in 0..1 {
222            let actual = assert_ends_with!(sequence, subsequence);
223            assert_eq!(actual, ());
224        }
225    }
226
227    #[test]
228    fn failure() {
229        let result = panic::catch_unwind(|| {
230            let sequence = "alfa";
231            let subsequence = "al";
232            let _actual = assert_ends_with!(sequence, subsequence);
233        });
234        let message = concat!(
235            "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
236            "https://docs.rs/assertables/",
237            env!("CARGO_PKG_VERSION"),
238            "/assertables/macro.assert_ends_with.html\n",
239            "     sequence label: `sequence`,\n",
240            "     sequence debug: `\"alfa\"`,\n",
241            "  subsequence label: `subsequence`,\n",
242            "  subsequence debug: `\"al\"`"
243        );
244        assert_eq!(
245            result
246                .unwrap_err()
247                .downcast::<String>()
248                .unwrap()
249                .to_string(),
250            message
251        );
252    }
253}
254
255/// Assert an expression (such as a string) ends with an expression (such as a string).
256///
257/// Pseudocode:<br>
258/// a.ends_with(b)
259///
260/// This macro provides the same statements as [`assert_ends_with`](macro.assert_ends_with.html),
261/// except this macro's statements are only enabled in non-optimized
262/// builds by default. An optimized build will not execute this macro's
263/// statements unless `-C debug-assertions` is passed to the compiler.
264///
265/// This macro is useful for checks that are too expensive to be present
266/// in a release build but may be helpful during development.
267///
268/// The result of expanding this macro is always type checked.
269///
270/// An unchecked assertion allows a program in an inconsistent state to
271/// keep running, which might have unexpected consequences but does not
272/// introduce unsafety as long as this only happens in safe code. The
273/// performance cost of assertions, however, is not measurable in general.
274/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
275/// after thorough profiling, and more importantly, only in safe code!
276///
277/// This macro is intended to work in a similar way to
278/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
279///
280/// # Module macros
281///
282/// * [`assert_ends_with`](macro@crate::assert_ends_with)
283/// * [`assert_ends_with`](macro@crate::assert_ends_with)
284/// * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
285///
286#[macro_export]
287macro_rules! debug_assert_ends_with {
288    ($($arg:tt)*) => {
289        if $crate::cfg!(debug_assertions) {
290            $crate::assert_ends_with!($($arg)*);
291        }
292    };
293}