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(
55 format!(
56 concat!(
57 "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
58 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_ends_with.html\n",
59 " sequence label: `{}`,\n",
60 " sequence debug: `{:?}`,\n",
61 " subsequence label: `{}`,\n",
62 " subsequence debug: `{:?}`",
63 ),
64 stringify!($sequence),
65 sequence,
66 stringify!($subsequence),
67 subsequence,
68 )
69 )
70 }
71 }
72 }
73 }};
74}
75
76#[cfg(test)]
77mod test_assert_ends_with_as_result {
78
79 #[test]
80 fn success() {
81 let sequence = "alfa";
82 let subsequence = "fa";
83 let actual = assert_ends_with_as_result!(sequence, subsequence);
84 assert_eq!(actual.unwrap(), ());
85 }
86
87 #[test]
88 fn failure() {
89 let sequence = "alfa";
90 let subsequence = "al";
91 let actual = assert_ends_with_as_result!(sequence, subsequence);
92 let message = concat!(
93 "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
94 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_ends_with.html\n",
95 " sequence label: `sequence`,\n",
96 " sequence debug: `\"alfa\"`,\n",
97 " subsequence label: `subsequence`,\n",
98 " subsequence debug: `\"al\"`"
99 );
100 assert_eq!(actual.unwrap_err(), message);
101 }
102}
103
104/// Assert an expression (such as a string) ends with an expression (such as a string).
105///
106/// Pseudocode:<br>
107/// a.ends_with(b)
108///
109/// * If true, return `()`.
110///
111/// * Otherwise, call [`panic!`] with a message and the values of the
112/// expressions with their debug representations.
113///
114/// # Examples
115///
116/// ```rust
117/// use assertables::*;
118/// # use std::panic;
119///
120/// # fn main() {
121/// // String ends with substring?
122/// let sequence: &str = "alfa";
123/// let subsequence: &str = "fa";
124/// assert_ends_with!(sequence, subsequence);
125///
126/// // Vector ends with element?
127/// let sequence = vec![1, 2, 3];
128/// let subsequence = [3];
129/// assert_ends_with!(sequence, subsequence);
130///
131/// # let result = panic::catch_unwind(|| {
132/// // This will panic
133/// let sequence = "alfa";
134/// let subsequence = "al";
135/// assert_ends_with!(sequence, subsequence);
136/// # });
137/// // assertion failed: `assert_ends_with!(sequence, subsequence)`
138/// // https://docs.rs/assertables/9.5.3/assertables/macro.assert_ends_with.html
139/// // sequence label: `sequence`,
140/// // sequence debug: `\"alfa\"`,
141/// // part label: `subsequence`,
142/// // part debug: `\"al\"`
143/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
144/// # let message = concat!(
145/// # "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
146/// # "https://docs.rs/assertables/9.5.3/assertables/macro.assert_ends_with.html\n",
147/// # " sequence label: `sequence`,\n",
148/// # " sequence debug: `\"alfa\"`,\n",
149/// # " subsequence label: `subsequence`,\n",
150/// # " subsequence debug: `\"al\"`"
151/// # );
152/// # assert_eq!(actual, message);
153/// # }
154/// ```
155///
156/// # Module macros
157///
158/// * [`assert_ends_with`](macro@crate::assert_ends_with)
159/// * [`assert_ends_with_as_result`](macro@crate::assert_ends_with_as_result)
160/// * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
161///
162#[macro_export]
163macro_rules! assert_ends_with {
164 ($sequence:expr, $subsequence:expr $(,)?) => {{
165 match $crate::assert_ends_with_as_result!($sequence, $subsequence) {
166 Ok(()) => (),
167 Err(err) => panic!("{}", err),
168 }
169 }};
170 ($sequence:expr, $subsequence:expr, $($message:tt)+) => {{
171 match $crate::assert_ends_with_as_result!($sequence, $subsequence) {
172 Ok(()) => (),
173 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
174 }
175 }};
176}
177
178#[cfg(test)]
179mod test_assert_ends_with {
180 use std::panic;
181
182 #[test]
183 fn success() {
184 let sequence = "alfa";
185 let subsequence = "fa";
186 let actual = assert_ends_with!(sequence, subsequence);
187 assert_eq!(actual, ());
188 }
189
190 #[test]
191 fn failure() {
192 let result = panic::catch_unwind(|| {
193 let sequence = "alfa";
194 let subsequence = "al";
195 let _actual = assert_ends_with!(sequence, subsequence);
196 });
197 let message = concat!(
198 "assertion failed: `assert_ends_with!(sequence, subsequence)`\n",
199 "https://docs.rs/assertables/9.5.3/assertables/macro.assert_ends_with.html\n",
200 " sequence label: `sequence`,\n",
201 " sequence debug: `\"alfa\"`,\n",
202 " subsequence label: `subsequence`,\n",
203 " subsequence debug: `\"al\"`"
204 );
205 assert_eq!(
206 result
207 .unwrap_err()
208 .downcast::<String>()
209 .unwrap()
210 .to_string(),
211 message
212 );
213 }
214}
215
216/// Assert an expression (such as a string) ends with an expression (such as a string).
217///
218/// Pseudocode:<br>
219/// a.ends_with(b)
220///
221/// This macro provides the same statements as [`assert_ends_with`](macro.assert_ends_with.html),
222/// except this macro's statements are only enabled in non-optimized
223/// builds by default. An optimized build will not execute this macro's
224/// statements unless `-C debug-assertions` is passed to the compiler.
225///
226/// This macro is useful for checks that are too expensive to be present
227/// in a release build but may be helpful during development.
228///
229/// The result of expanding this macro is always type checked.
230///
231/// An unchecked assertion allows a program in an inconsistent state to
232/// keep running, which might have unexpected consequences but does not
233/// introduce unsafety as long as this only happens in safe code. The
234/// performance cost of assertions, however, is not measurable in general.
235/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
236/// after thorough profiling, and more importantly, only in safe code!
237///
238/// This macro is intended to work in a similar way to
239/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
240///
241/// # Module macros
242///
243/// * [`assert_ends_with`](macro@crate::assert_ends_with)
244/// * [`assert_ends_with`](macro@crate::assert_ends_with)
245/// * [`debug_assert_ends_with`](macro@crate::debug_assert_ends_with)
246///
247#[macro_export]
248macro_rules! debug_assert_ends_with {
249 ($($arg:tt)*) => {
250 if $crate::cfg!(debug_assertions) {
251 $crate::assert_ends_with!($($arg)*);
252 }
253 };
254}