Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 120 additions & 12 deletions src/assert_contains/assert_contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
//!
//! Pseudocode:<br>
//! a.contains(b)
//! or
//! a.iter().any(|item| item == *b)
//!
//! These macros work with many kinds of Rust types, such as String, Vec, Range, HashSet.
//! The specifics depend on each type's implementation of a method `contains`, and some types
//! require the second argument to be borrowable, so be sure to check the Rust documentation.
//! These macros work with many kinds of Rust types, such as String, Vec, Range,
//! HashSet and any IntoIterator. The specifics depend on each type's implementation of
//! a method `contains`. Or you can add the `=> IntoIterator` to the container like
//! `assert_contains(a => IntoIterator, &b)` to iterate over the container instead
//! of relying on a potentially-missing `contains` method.
//! Some types require the second argument to be borrowable,
//! so be sure to check the Rust documentation.
//!
//! # Example
//!
Expand All @@ -24,6 +30,15 @@
//! let b = 2;
//! assert_contains!(a, &b);
//!
//! // An iterable that does not implement the "contains" method.
//! // Notice the `=> IntoIterator` separator/identifier to make it clear that you want
//! // to iterate over every item of the container to look for the containee.
//! let a = std::collections::BinaryHeap::new();
//! heap.push(5);
//! heap.push(2);
//! let b = 2;
//! assert_contains!(a => IntoIterator, &b);
//!
//! // Vector contains element.
//! // Notice the &b because the macro calls Vec.contains(&self, &value).
//! let a = vec![1, 2, 3];
Expand Down Expand Up @@ -67,24 +82,43 @@
/// * [`assert_contains`](macro@crate::assert_contains)
/// * [`assert_contains_as_result`](macro@crate::assert_contains_as_result)
/// * [`debug_assert_contains`](macro@crate::debug_assert_contains)
///
#[macro_export]
macro_rules! assert_contains_as_result {
(@msg) => {
concat!(
"assertion failed: `assert_contains!(container, containee)`\n",
"https://docs.rs/assertables/9.8.3/assertables/macro.assert_contains.html\n",
" container label: `{}`,\n",
" container debug: `{:?}`,\n",
" containee label: `{}`,\n",
" containee debug: `{:?}`",
)
};
($container:expr => IntoIterator, $containee:expr $(,)?) => {
match (&$container, &$containee) {
(container, containee) => {
if container.into_iter().any(|x| x == *containee) {
Ok(())
} else {
Err(format!(
$crate::assert_contains_as_result!(@msg),
stringify!($container),
container,
stringify!($containee),
containee,
))
}
}
}
};
($container:expr, $containee:expr $(,)?) => {
match (&$container, &$containee) {
(container, containee) => {
if (container).contains(*containee) {
Ok(())
} else {
Err(format!(
concat!(
"assertion failed: `assert_contains!(container, containee)`\n",
"https://docs.rs/assertables/9.8.3/assertables/macro.assert_contains.html\n",
" container label: `{}`,\n",
" container debug: `{:?}`,\n",
" containee label: `{}`,\n",
" containee debug: `{:?}`",
),
$crate::assert_contains_as_result!(@msg),
stringify!($container),
container,
stringify!($containee),
Expand Down Expand Up @@ -283,6 +317,68 @@ mod test_assert_contains_as_result {
}
}

mod binary_heap_string {
use super::*;
use std::collections::BinaryHeap;

#[test]
fn success() {
let a: BinaryHeap<String> =
BinaryHeap::from(vec![String::from("1"), String::from("3")]);
let b: String = String::from("2");
for _ in 0..1 {
let actual = assert_contains_as_result!(a => IntoIterator, &b);
assert_eq!(actual.unwrap(), ());
}
}

#[test]
fn success_once() {
static A: Once = Once::new();
fn a() -> BinaryHeap<String> {
if A.is_completed() {
panic!("A.is_completed()")
} else {
A.call_once(|| {})
}
BinaryHeap::from(vec![String::from("1"), String::from("3")])
}

static B: Once = Once::new();
fn b() -> String {
if B.is_completed() {
panic!("B.is_completed()")
} else {
B.call_once(|| {})
}
String::from("2")
}

assert_eq!(A.is_completed(), false);
assert_eq!(B.is_completed(), false);
let result = assert_contains_as_result!(a() => IntoIterator, &b());
assert!(result.is_ok());
assert_eq!(A.is_completed(), true);
assert_eq!(B.is_completed(), true);
}

#[test]
fn failure() {
let a = BinaryHeap::from(vec![String::from("1"), String::from("3")]);
let b: String = String::from("4");
let actual = assert_contains_as_result!(a => IntoIterator, &b);
let message = concat!(
"assertion failed: `assert_contains!(container, containee)`\n",
"https://docs.rs/assertables/9.8.2/assertables/macro.assert_contains.html\n",
" container label: `a`,\n",
" container debug: `\"1\"..\"3\"`,\n",
" containee label: `&b`,\n",
" containee debug: `\"4\"`"
);
assert_eq!(actual.unwrap_err(), message);
}
}

mod vec_i32 {
use super::*;

Expand Down Expand Up @@ -604,6 +700,18 @@ mod test_assert_contains_as_result {
///
#[macro_export]
macro_rules! assert_contains {
($container:expr => IntoIterator , $containee:expr $(,)?) => {
match $crate::assert_contains_as_result!($container => IntoIterator, $containee) {
Ok(()) => (),
Err(err) => panic!("{}", err),
}
};
($container:expr => IntoIterator, $containee:expr, $($message:tt)+) => {
match $crate::assert_contains_as_result!($container => IntoIterator, $containee) {
Ok(()) => (),
Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
}
};
($container:expr, $containee:expr $(,)?) => {
match $crate::assert_contains_as_result!($container, $containee) {
Ok(()) => (),
Expand Down