diff --git a/src/assert_any.rs b/src/assert_any/assert_any.rs similarity index 100% rename from src/assert_any.rs rename to src/assert_any/assert_any.rs diff --git a/src/assert_any/assert_any_eq.rs b/src/assert_any/assert_any_eq.rs new file mode 100644 index 00000000..025a92f4 --- /dev/null +++ b/src/assert_any/assert_any_eq.rs @@ -0,0 +1,267 @@ +//! Assert an iter contains an element. +//! +//! Pseudocode:
+//! (collection1 into iter) contains (item) +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 1; +//! assert_any_eq!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_eq`](macro@crate::assert_any_eq) +//! * [`assert_any_eq_as_result`](macro@crate::assert_any_eq_as_result) +//! * [`debug_assert_any_eq`](macro@crate::debug_assert_any_eq) + +/// Assert an iter contains an element. +/// +/// Pseudocode:
+/// (collection1 into iter) contains (item) +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_eq`](macro@crate::assert_any_eq) +/// * [`assert_any_eq_as_result`](macro@crate::assert_any_eq_as_result) +/// * [`debug_assert_any_eq`](macro@crate::debug_assert_any_eq) +/// +#[macro_export] +macro_rules! assert_any_eq_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x == b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_eq!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_eq.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_eq_as_result { + // use std::sync::Once; + + #[test] + fn success_int() { + let a = [1, 2]; + let b = 1; + for _ in 0..1 { + let actual = assert_any_eq_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn success_struct() { + #[derive(Debug, PartialEq)] + struct Point { + x: i32, + y: i32, + } + let points: [Point; 2] = [Point { x: 1, y: 2 }, Point { x: 2, y: 3 }]; + let point = Point { x: 1, y: 2 }; + for _ in 0..1 { + let actual = assert_any_eq_as_result!(&points, &point); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn failure() { + let a = [1, 2]; + let b = 0; + let actual = assert_any_eq_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_eq!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_eq.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `0`" + ); + assert_eq!(actual.unwrap_err(), message); + } +} + +/// Assert an iterable is equal to another. +/// +/// Pseudocode:
+/// (collection1 into iter) = (collection2 into iter) +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [1, 2]; +/// let b = 1; +/// assert_any_eq!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [1, 2]; +/// let b = 0; +/// assert_any_eq!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_eq!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_eq.html +/// // a label: `&a`, +/// // a debug: `[1, 2]`, +/// // b label: `&b`, +/// // b debug: `0` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_eq!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_eq.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[1, 2]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `0`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_eq`](macro@crate::assert_any_eq) +/// * [`assert_any_eq_as_result`](macro@crate::assert_any_eq_as_result) +/// * [`debug_assert_any_eq`](macro@crate::debug_assert_any_eq) +/// +#[macro_export] +macro_rules! assert_any_eq { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_eq_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_eq_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_eq { + use std::panic; + + #[test] + fn success() { + let a = [1, 2]; + let b = 2; + for _ in 0..1 { + let actual = assert_any_eq!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn failure() { + let a = [1, 2]; + let b = 0; + let result = panic::catch_unwind(|| { + let _actual = assert_any_eq!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_eq!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_eq.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `0`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is equal to another. +/// +/// Pseudocode:
+/// (collection1 into iter) = (collection2 into iter) +/// +/// This macro provides the same statements as [`assert_any_eq`](macro.assert_any_eq.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_eq`](macro@crate::assert_any_eq) +/// * [`assert_any_eq`](macro@crate::assert_any_eq) +/// * [`debug_assert_any_eq`](macro@crate::debug_assert_any_eq) +/// +#[macro_export] +macro_rules! debug_assert_any_eq { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_eq!($($arg)*); + } + }; +} diff --git a/src/assert_any/assert_any_ge.rs b/src/assert_any/assert_any_ge.rs new file mode 100644 index 00000000..3e387b57 --- /dev/null +++ b/src/assert_any/assert_any_ge.rs @@ -0,0 +1,293 @@ +//! Assert an iter is greater than or equal to another. +//! +//! Pseudocode:
+//! (collection into iter) ≥ item +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 2; +//! assert_any_ge!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_ge`](macro@crate::assert_any_ge) +//! * [`assert_any_ge_as_result`](macro@crate::assert_any_ge_as_result) +//! * [`debug_assert_any_ge`](macro@crate::debug_assert_any_ge) + +/// Assert an iterable is greater than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≥ item +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_ge`](macro@crate::assert_any_ge) +/// * [`assert_any_ge_as_result`](macro@crate::assert_any_ge_as_result) +/// * [`debug_assert_any_ge`](macro@crate::debug_assert_any_ge) +/// +#[macro_export] +macro_rules! assert_any_ge_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x >= b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_ge!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ge.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_ge_as_result { + // use std::sync::Once; + + #[test] + fn gt() { + let a = [3, 7]; + let b = 5; + for _ in 0..1 { + let actual = assert_any_ge_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 1; + for _ in 0..1 { + let actual = assert_any_ge_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn lt() { + let a = [1, 2]; + let b = 3; + let actual = assert_any_ge_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_ge!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ge.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `3`" + ); + assert_eq!(actual.unwrap_err(), message); + } + + #[test] + fn success_struct() { + use std::cmp::Ordering; + #[derive(Debug, PartialEq)] + struct Point { + x: i32, + } + impl PartialOrd for Point { + fn partial_cmp(&self, other: &Self) -> Option { + // Reuses the implementation of the field's type (u32) + self.x.partial_cmp(&other.x) + } + } + let points: [Point; 2] = [Point { x: 1 }, Point { x: 2 }]; + let point = Point { x: 1 }; + for _ in 0..1 { + let actual = assert_any_ge_as_result!(&points, &point); + assert_eq!(actual.unwrap(), ()); + } + } +} + +/// Assert an iterable is greater than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≥ item +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [3, 4]; +/// let b = 4; +/// assert_any_ge!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [1, 2]; +/// let b = 5; +/// assert_any_ge!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_ge!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_ge.html +/// // a label: `&a`, +/// // a debug: `[1, 2]`, +/// // b label: `&b`, +/// // b debug: `5` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_ge!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ge.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[1, 2]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `5`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_ge`](macro@crate::assert_any_ge) +/// * [`assert_any_ge_as_result`](macro@crate::assert_any_ge_as_result) +/// * [`debug_assert_any_ge`](macro@crate::debug_assert_any_ge) +/// +#[macro_export] +macro_rules! assert_any_ge { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_ge_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_ge_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_ge { + use std::panic; + + #[test] + fn gt() { + let a = [3, 7]; + let b = 5; + for _ in 0..1 { + let actual = assert_any_ge!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 2; + for _ in 0..1 { + let actual = assert_any_ge!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn lt() { + let a = [1, 2]; + let b = 3; + let result = panic::catch_unwind(|| { + let _actual = assert_any_ge!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_ge!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ge.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `3`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is greater than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≥ item +/// +/// This macro provides the same statements as [`assert_any_ge`](macro.assert_any_ge.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_ge`](macro@crate::assert_any_ge) +/// * [`assert_any_ge`](macro@crate::assert_any_ge) +/// * [`debug_assert_any_ge`](macro@crate::debug_assert_any_ge) +/// +#[macro_export] +macro_rules! debug_assert_any_ge { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_ge!($($arg)*); + } + }; +} diff --git a/src/assert_any/assert_any_gt.rs b/src/assert_any/assert_any_gt.rs new file mode 100644 index 00000000..85862cb1 --- /dev/null +++ b/src/assert_any/assert_any_gt.rs @@ -0,0 +1,293 @@ +//! Assert an iter is greater than another. +//! +//! Pseudocode:
+//! (collection into iter) > item +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [3, 4]; +//! let b = 2; +//! assert_any_gt!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_gt`](macro@crate::assert_any_gt) +//! * [`assert_any_gt_as_result`](macro@crate::assert_any_gt_as_result) +//! * [`debug_assert_any_gt`](macro@crate::debug_assert_any_gt) + +/// Assert an iterable is greater than another. +/// +/// Pseudocode:
+/// (collection into iter) > item +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_gt`](macro@crate::assert_any_gt) +/// * [`assert_any_gt_as_result`](macro@crate::assert_any_gt_as_result) +/// * [`debug_assert_any_gt`](macro@crate::debug_assert_any_gt) +/// +#[macro_export] +macro_rules! assert_any_gt_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x > b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_gt_as_result { + // use std::sync::Once; + + #[test] + fn gt() { + let a = [3, 7]; + let b = 4; + for _ in 0..1 { + let actual = assert_any_gt_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 2; + let actual = assert_any_gt_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!(actual.unwrap_err(), message); + } + + #[test] + fn lt() { + let a = [1, 2]; + let b = 5; + let actual = assert_any_gt_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `5`" + ); + assert_eq!(actual.unwrap_err(), message); + } +} + +/// Assert an iterable is greater than another. +/// +/// Pseudocode:
+/// (collection into iter) > item +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [3, 4]; +/// let b = 3; +/// assert_any_gt!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [1, 2]; +/// let b = 2; +/// assert_any_gt!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_gt!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_gt.html +/// // a label: `&a`, +/// // a debug: `[1, 2]`, +/// // b label: `&b`, +/// // b debug: `2` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[1, 2]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `2`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_gt`](macro@crate::assert_any_gt) +/// * [`assert_any_gt_as_result`](macro@crate::assert_any_gt_as_result) +/// * [`debug_assert_any_gt`](macro@crate::debug_assert_any_gt) +/// +#[macro_export] +macro_rules! assert_any_gt { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_gt_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_gt_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_gt { + use std::panic; + + #[test] + fn gt() { + let a = [3, 7]; + let b = 4; + for _ in 0..1 { + let actual = assert_any_gt!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 2; + let result = panic::catch_unwind(|| { + let _actual = assert_any_gt!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } + + #[test] + fn lt() { + let a = [1, 2]; + let b = 5; + let result = panic::catch_unwind(|| { + let _actual = assert_any_gt!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_gt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_gt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `5`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is greater than another. +/// +/// Pseudocode:
+/// (collection into iter) > item +/// +/// This macro provides the same statements as [`assert_any_gt`](macro.assert_any_gt.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_gt`](macro@crate::assert_any_gt) +/// * [`assert_any_gt`](macro@crate::assert_any_gt) +/// * [`debug_assert_any_gt`](macro@crate::debug_assert_any_gt) +/// +#[macro_export] +macro_rules! debug_assert_any_gt { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_gt!($($arg)*); + } + }; +} diff --git a/src/assert_any/assert_any_le.rs b/src/assert_any/assert_any_le.rs new file mode 100644 index 00000000..ba555687 --- /dev/null +++ b/src/assert_any/assert_any_le.rs @@ -0,0 +1,272 @@ +//! Assert an iter is less than or equal to another. +//! +//! Pseudocode:
+//! (collection into iter) ≤ item +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 3; +//! assert_any_le!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_le`](macro@crate::assert_any_le) +//! * [`assert_any_le_as_result`](macro@crate::assert_any_le_as_result) +//! * [`debug_assert_any_le`](macro@crate::debug_assert_any_le) + +/// Assert an iterable is less than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≤ item +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_le`](macro@crate::assert_any_le) +/// * [`assert_any_le_as_result`](macro@crate::assert_any_le_as_result) +/// * [`debug_assert_any_le`](macro@crate::debug_assert_any_le) +/// +#[macro_export] +macro_rules! assert_any_le_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x <= b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_le!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_le.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_le_as_result { + // use std::sync::Once; + + #[test] + fn lt() { + let a = [1, 2]; + let b = 2; + for _ in 0..1 { + let actual = assert_any_le_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 1; + for _ in 0..1 { + let actual = assert_any_le_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn gt() { + let a = [3, 4]; + let b = 2; + let actual = assert_any_le_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_le!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_le.html\n", + " a label: `&a`,\n", + " a debug: `[3, 4]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!(actual.unwrap_err(), message); + } +} + +/// Assert an iterable is less than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≤ item +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [1, 2]; +/// let b = 1; +/// assert_any_le!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [3, 4]; +/// let b = 2; +/// assert_any_le!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_le!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_le.html +/// // a label: `&a`, +/// // a debug: `[3, 4]`, +/// // b label: `&b`, +/// // b debug: `2` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_le!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_le.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[3, 4]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `2`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_le`](macro@crate::assert_any_le) +/// * [`assert_any_le_as_result`](macro@crate::assert_any_le_as_result) +/// * [`debug_assert_any_le`](macro@crate::debug_assert_any_le) +/// +#[macro_export] +macro_rules! assert_any_le { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_le_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_le_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_le { + use std::panic; + + #[test] + fn lt() { + let a = [1, 2]; + let b = 5; + for _ in 0..1 { + let actual = assert_any_le!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 1; + for _ in 0..1 { + let actual = assert_any_le!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn gt() { + let a = [3, 4]; + let b = 2; + let result = panic::catch_unwind(|| { + let _actual = assert_any_le!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_le!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_le.html\n", + " a label: `&a`,\n", + " a debug: `[3, 4]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is less than or equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≤ item +/// +/// This macro provides the same statements as [`assert_any_le`](macro.assert_any_le.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_le`](macro@crate::assert_any_le) +/// * [`assert_any_le`](macro@crate::assert_any_le) +/// * [`debug_assert_any_le`](macro@crate::debug_assert_any_le) +/// +#[macro_export] +macro_rules! debug_assert_any_le { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_le!($($arg)*); + } + }; +} diff --git a/src/assert_any/assert_any_lt.rs b/src/assert_any/assert_any_lt.rs new file mode 100644 index 00000000..3b1cfd63 --- /dev/null +++ b/src/assert_any/assert_any_lt.rs @@ -0,0 +1,293 @@ +//! Assert an iter is less than another. +//! +//! Pseudocode:
+//! (collection into iter) < item +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 3; +//! assert_any_lt!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_lt`](macro@crate::assert_any_lt) +//! * [`assert_any_lt_as_result`](macro@crate::assert_any_lt_as_result) +//! * [`debug_assert_any_lt`](macro@crate::debug_assert_any_lt) + +/// Assert an iterable is less than another. +/// +/// Pseudocode:
+/// (collection into iter) < item +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_lt`](macro@crate::assert_any_lt) +/// * [`assert_any_lt_as_result`](macro@crate::assert_any_lt_as_result) +/// * [`debug_assert_any_lt`](macro@crate::debug_assert_any_lt) +/// +#[macro_export] +macro_rules! assert_any_lt_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x < b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_lt_as_result { + // use std::sync::Once; + + #[test] + fn lt() { + let a = [1, 2]; + let b = 3; + for _ in 0..1 { + let actual = assert_any_lt_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 1; + let actual = assert_any_lt_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `1`" + ); + assert_eq!(actual.unwrap_err(), message); + } + + #[test] + fn gt() { + let a = [3, 4]; + let b = 2; + let actual = assert_any_lt_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", + " a label: `&a`,\n", + " a debug: `[3, 4]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!(actual.unwrap_err(), message); + } +} + +/// Assert an iterable is less than another. +/// +/// Pseudocode:
+/// (collection into iter) < item +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [1, 2]; +/// let b = 3; +/// assert_any_lt!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [3, 4]; +/// let b = 2; +/// assert_any_lt!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_lt!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_lt.html +/// // a label: `&a`, +/// // a debug: `[3, 4]`, +/// // b label: `&b`, +/// // b debug: `2` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[3, 4]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `2`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_lt`](macro@crate::assert_any_lt) +/// * [`assert_any_lt_as_result`](macro@crate::assert_any_lt_as_result) +/// * [`debug_assert_any_lt`](macro@crate::debug_assert_any_lt) +/// +#[macro_export] +macro_rules! assert_any_lt { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_lt_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_lt_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_lt { + use std::panic; + + #[test] + fn lt() { + let a = [1, 2]; + let b = 2; + for _ in 0..1 { + let actual = assert_any_lt!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn eq() { + let a = [1, 2]; + let b = 1; + let result = panic::catch_unwind(|| { + let _actual = assert_any_lt!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", + " a label: `&a`,\n", + " a debug: `[1, 2]`,\n", + " b label: `&b`,\n", + " b debug: `1`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } + + #[test] + fn gt() { + let a = [3, 4]; + let b = 2; + let result = panic::catch_unwind(|| { + let _actual = assert_any_lt!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_lt!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_lt.html\n", + " a label: `&a`,\n", + " a debug: `[3, 4]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is less than another. +/// +/// Pseudocode:
+/// (collection into iter) < item +/// +/// This macro provides the same statements as [`assert_any_lt`](macro.assert_any_lt.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_lt`](macro@crate::assert_any_lt) +/// * [`assert_any_lt`](macro@crate::assert_any_lt) +/// * [`debug_assert_any_lt`](macro@crate::debug_assert_any_lt) +/// +#[macro_export] +macro_rules! debug_assert_any_lt { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_lt!($($arg)*); + } + }; +} diff --git a/src/assert_any/assert_any_ne.rs b/src/assert_any/assert_any_ne.rs new file mode 100644 index 00000000..72298097 --- /dev/null +++ b/src/assert_any/assert_any_ne.rs @@ -0,0 +1,252 @@ +//! Assert an iter is not equal to another. +//! +//! Pseudocode:
+//! (collection into iter) ≠ item +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 1; +//! assert_any_ne!(&a, &b); +//! ``` +//! +//! This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +//! +//! # Module macros +//! +//! * [`assert_any_ne`](macro@crate::assert_any_ne) +//! * [`assert_any_ne_as_result`](macro@crate::assert_any_ne_as_result) +//! * [`debug_assert_any_ne`](macro@crate::debug_assert_any_ne) + +/// Assert an iterable is not equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≠ item +/// +/// * If true, return Result `Ok(())`. +/// +/// * Otherwise, return Result `Err(message)`. +/// +/// This macro is useful for runtime checks, such as checking parameters, +/// or sanitizing inputs, or handling different results in different ways. +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_ne`](macro@crate::assert_any_ne) +/// * [`assert_any_ne_as_result`](macro@crate::assert_any_ne_as_result) +/// * [`debug_assert_any_ne`](macro@crate::debug_assert_any_ne) +/// +#[macro_export] +macro_rules! assert_any_ne_as_result { + ($a_collection:expr, $b_item:expr $(,)?) => { + match ($a_collection, $b_item) { + (a_collection, b_item) => { + let mut a = a_collection.into_iter(); + if a.any(|x| x != b_item) { + Ok(()) + } else { + Err(format!( + concat!( + "assertion failed: `assert_any_ne!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ne.html\n", + " a label: `{}`,\n", + " a debug: `{:?}`,\n", + " b label: `{}`,\n", + " b debug: `{:?}`" + ), + stringify!($a_collection), + a_collection, + stringify!($b_item), + b_item + )) + } + } + } + }; +} + +#[cfg(test)] +mod test_assert_any_ne_as_result { + // use std::sync::Once; + + #[test] + fn success() { + let a = [2, 2]; + let b = 1; + for _ in 0..1 { + let actual = assert_any_ne_as_result!(&a, &b); + assert_eq!(actual.unwrap(), ()); + } + } + + #[test] + fn failure() { + let a = [2, 2]; + let b = 2; + let actual = assert_any_ne_as_result!(&a, &b); + let message = concat!( + "assertion failed: `assert_any_ne!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ne.html\n", + " a label: `&a`,\n", + " a debug: `[2, 2]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!(actual.unwrap_err(), message); + } +} + +/// Assert an iterable is not equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≠ item +/// +/// * If true, return `()`. +/// +/// * Otherwise, call [`panic!`] with a message and the values of the +/// expressions with their debug representations. +/// +/// # Examples +/// +/// ```rust +/// use assertables::*; +/// # use std::panic; +/// +/// # fn main() { +/// let a = [1, 2]; +/// let b = 2; +/// assert_any_ne!(&a, &b); +/// +/// # let result = panic::catch_unwind(|| { +/// // This will panic +/// let a = [2, 2]; +/// let b = 2; +/// assert_any_ne!(&a, &b); +/// # }); +/// // assertion failed: `assert_any_ne!(a_collection, b_item)` +/// // https://docs.rs/assertables/…/assertables/macro.assert_any_ne.html +/// // a label: `&a`, +/// // a debug: `[2, 2]`, +/// // b label: `&b`, +/// // b debug: `2` +/// # let actual = result.unwrap_err().downcast::().unwrap().to_string(); +/// # let message = concat!( +/// # "assertion failed: `assert_any_ne!(a_collection, b_item)`\n", +/// # "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ne.html\n", +/// # " a label: `&a`,\n", +/// # " a debug: `[2, 2]`,\n", +/// # " b label: `&b`,\n", +/// # " b debug: `2`", +/// # ); +/// # assert_eq!(actual, message); +/// # } +/// ``` +/// +/// This implementation uses [`::std::iter::Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html). +/// +/// # Module macros +/// +/// * [`assert_any_ne`](macro@crate::assert_any_ne) +/// * [`assert_any_ne_as_result`](macro@crate::assert_any_ne_as_result) +/// * [`debug_assert_any_ne`](macro@crate::debug_assert_any_ne) +/// +#[macro_export] +macro_rules! assert_any_ne { + ($a_collection:expr, $b_item:expr $(,)?) => { + match $crate::assert_any_ne_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}", err), + } + }; + ($a_collection:expr, $b_item:expr, $($message:tt)+) => { + match $crate::assert_any_ne_as_result!($a_collection, $b_item) { + Ok(()) => (), + Err(err) => panic!("{}\n{}", format_args!($($message)+), err), + } + }; +} + +#[cfg(test)] +mod test_assert_any_ne { + use std::panic; + + #[test] + fn success() { + let a = [1, 2]; + let b = 2; + for _ in 0..1 { + let actual = assert_any_ne!(&a, &b); + assert_eq!(actual, ()); + } + } + + #[test] + fn failure() { + let a = [2, 2]; + let b = 2; + let result = panic::catch_unwind(|| { + let _actual = assert_any_ne!(&a, &b); + }); + let message = concat!( + "assertion failed: `assert_any_ne!(a_collection, b_item)`\n", + "https://docs.rs/assertables/9.8.4/assertables/macro.assert_any_ne.html\n", + " a label: `&a`,\n", + " a debug: `[2, 2]`,\n", + " b label: `&b`,\n", + " b debug: `2`" + ); + assert_eq!( + result + .unwrap_err() + .downcast::() + .unwrap() + .to_string(), + message + ); + } +} + +/// Assert an iterable is not equal to another. +/// +/// Pseudocode:
+/// (collection into iter) ≠ item +/// +/// This macro provides the same statements as [`assert_any_ne`](macro.assert_any_ne.html), +/// except this macro's statements are only enabled in non-optimized +/// builds by default. An optimized build will not execute this macro's +/// statements unless `-C debug-assertions` is passed to the compiler. +/// +/// This macro is useful for checks that are too expensive to be present +/// in a release build but may be helpful during development. +/// +/// The result of expanding this macro is always type checked. +/// +/// An unchecked assertion allows a program in an inconsistent state to +/// keep running, which might have unexpected consequences but does not +/// introduce unsafety as long as this only happens in safe code. The +/// performance cost of assertions, however, is not measurable in general. +/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged +/// after thorough profiling, and more importantly, only in safe code! +/// +/// This macro is intended to work in a similar way to +/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html). +/// +/// # Module macros +/// +/// * [`assert_any_ne`](macro@crate::assert_any_ne) +/// * [`assert_any_ne`](macro@crate::assert_any_ne) +/// * [`debug_assert_any_ne`](macro@crate::debug_assert_any_ne) +/// +#[macro_export] +macro_rules! debug_assert_any_ne { + ($($arg:tt)*) => { + if $crate::cfg!(debug_assertions) { + $crate::assert_any_ne!($($arg)*); + } + }; +} diff --git a/src/assert_any/mod.rs b/src/assert_any/mod.rs new file mode 100644 index 00000000..d8a312a5 --- /dev/null +++ b/src/assert_any/mod.rs @@ -0,0 +1,31 @@ +//! Assert for comparing an iter collection with a single element. +//! +//! These macros help with comparison of iter parameters, such as a collection of struct +//! and a single struct. +//! These macros convert each input using the std::iter::Iterator trait. +//! +//! * [`assert_any_eq!(collection, item)`](macro@crate::assert_any_eq) ≈ iter a contains b +//! * [`assert_any_ne!(collection, item)`](macro@crate::assert_any_ne) ≈ iter a does not contain b +//! * [`assert_any_lt!(collection, item)`](macro@crate::assert_any_gt) ≈ iter a contains ≥ one element < b +//! * [`assert_any_le!(collection, item)`](macro@crate::assert_any_gt) ≈ iter a contains ≥ one element ≤ b +//! * [`assert_any_gt!(collection, item)`](macro@crate::assert_any_gt) ≈ iter a contains ≥ one element > b +//! * [`assert_any_ge!(collection, item)`](macro@crate::assert_any_ge) ≈ iter a contains ≥ one element ≥ b +//! +//! # Example +//! +//! ```rust +//! use assertables::*; +//! +//! let a = [1, 2]; +//! let b = 1; +//! assert_any_eq!(&a, &b); +//! ``` + +// Comparisons +pub mod assert_any; +pub mod assert_any_eq; +pub mod assert_any_ge; +pub mod assert_any_gt; +pub mod assert_any_le; +pub mod assert_any_lt; +pub mod assert_any_ne;