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}