assertables/assert_starts_with/
assert_not_starts_with.rs

1//! Assert an expression (such as a string) does not start with an expression (such as a string).
2//!
3//! Pseudocode:<br>
4//! ¬ a.starts_with(b)
5//!
6//! # Example
7//!
8//! ```rust
9//! use assertables::*;
10//!
11//! // String starts with substring?
12//! let sequence: &str = "alfa";
13//! let subsequence: &str = "z";
14//! assert_not_starts_with!(sequence, subsequence);
15//!
16//! // Vector starts with element?
17//! let sequence = vec![1, 2, 3];
18//! let subsequence = [3];
19//! assert_not_starts_with!(sequence, subsequence);
20//! ```
21//!
22//! # Module macros
23//!
24//! * [`assert_not_starts_with`](macro@crate::assert_not_starts_with)
25//! * [`assert_not_starts_with_as_result`](macro@crate::assert_not_starts_with_as_result)
26//! * [`debug_assert_not_starts_with`](macro@crate::debug_assert_not_starts_with)
27
28/// Assert an expression (such as a string) does not start with an expression (such as a substring).
29///
30/// Pseudocode:<br>
31/// ¬ a.starts_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_not_starts_with`](macro@crate::assert_not_starts_with)
43/// * [`assert_not_starts_with_as_result`](macro@crate::assert_not_starts_with_as_result)
44/// * [`debug_assert_not_starts_with`](macro@crate::debug_assert_not_starts_with)
45///
46#[macro_export]
47macro_rules! assert_not_starts_with_as_result {
48    ($sequence:expr, $subsequence:expr $(,)?) => {{
49        match (&$sequence, &$subsequence) {
50            (sequence, subsequence) => {
51                if !(sequence.starts_with(subsequence)) {
52                    Ok(())
53                } else {
54                    Err(
55                        format!(
56                            concat!(
57                                "assertion failed: `assert_not_starts_with!(sequence, subsequence)`\n",
58                                "https://docs.rs/assertables/9.5.4/assertables/macro.assert_not_starts_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_not_starts_with_as_result {
78
79    #[test]
80    fn success() {
81        let sequence = "alfa";
82        let subsequence = "fa";
83        let actual = assert_not_starts_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_not_starts_with_as_result!(sequence, subsequence);
92        let message = concat!(
93            "assertion failed: `assert_not_starts_with!(sequence, subsequence)`\n",
94            "https://docs.rs/assertables/9.5.4/assertables/macro.assert_not_starts_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) does not start with an expression (such as a string).
105///
106/// Pseudocode:<br>
107/// ¬ a.starts_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 starts with substring?
122/// let sequence: &str = "alfa";
123/// let subsequence: &str = "z";
124/// assert_not_starts_with!(sequence, subsequence);
125///
126/// // Vector starts with element?
127/// let sequence = vec![1, 2, 3];
128/// let subsequence = [3];
129/// assert_not_starts_with!(sequence, subsequence);
130///
131/// # let result = panic::catch_unwind(|| {
132/// // This will panic
133/// let sequence = "alfa";
134/// let subsequence = "al";
135/// assert_not_starts_with!(sequence, subsequence);
136/// # });
137/// // assertion failed: `assert_not_starts_with!(sequence, subsequence)`
138/// // https://docs.rs/assertables/9.5.4/assertables/macro.assert_not_starts_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_not_starts_with!(sequence, subsequence)`\n",
146/// #     "https://docs.rs/assertables/9.5.4/assertables/macro.assert_not_starts_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_not_starts_with`](macro@crate::assert_not_starts_with)
159/// * [`assert_not_starts_with_as_result`](macro@crate::assert_not_starts_with_as_result)
160/// * [`debug_assert_not_starts_with`](macro@crate::debug_assert_not_starts_with)
161///
162#[macro_export]
163macro_rules! assert_not_starts_with {
164    ($sequence:expr, $subsequence:expr $(,)?) => {{
165        match $crate::assert_not_starts_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_not_starts_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_not_starts_with {
180    use std::panic;
181
182    #[test]
183    fn success() {
184        let sequence = "alfa";
185        let subsequence = "fa";
186        let actual = assert_not_starts_with!(sequence, subsequence);
187        assert_eq!(actual, ());
188    }
189
190    #[test]
191    fn failure() {
192        let sequence = "alfa";
193        let subsequence = "al";
194        let result = panic::catch_unwind(|| {
195            let _actual = assert_not_starts_with!(sequence, subsequence);
196        });
197        let message = concat!(
198            "assertion failed: `assert_not_starts_with!(sequence, subsequence)`\n",
199            "https://docs.rs/assertables/9.5.4/assertables/macro.assert_not_starts_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) does not start with an expression (such as a string).
217///
218/// Pseudocode:<br>
219/// ¬ a.starts_with(b)
220///
221/// This macro provides the same statements as [`assert_not_starts_with`](macro.assert_not_starts_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_not_starts_with`](macro@crate::assert_not_starts_with)
244/// * [`assert_not_starts_with`](macro@crate::assert_not_starts_with)
245/// * [`debug_assert_not_starts_with`](macro@crate::debug_assert_not_starts_with)
246///
247#[macro_export]
248macro_rules! debug_assert_not_starts_with {
249    ($($arg:tt)*) => {
250        if $crate::cfg!(debug_assertions) {
251            $crate::assert_not_starts_with!($($arg)*);
252        }
253    };
254}