use alloc::vec::Vec;
use core::fmt::Debug;
use crate::{AssertThat, AssertrPartialEq, Mode, prelude::SliceAssertions};
#[allow(clippy::return_self_not_must_use)]
#[cfg_attr(feature = "fluent", assertr_derive::fluent_aliases)]
pub trait VecAssertions<'t, T: Debug> {
fn contains<E>(self, expected: E) -> Self
where
E: Debug,
T: AssertrPartialEq<E> + Debug;
fn contains_exactly<E>(self, expected: impl AsRef<[E]>) -> Self
where
E: Debug + 't,
T: AssertrPartialEq<E> + Debug;
fn contains_exactly_in_any_order<E: AsRef<[T]>>(self, expected: E) -> Self
where
T: PartialEq + Debug;
fn contains_exactly_matching_in_any_order<P>(self, expected: impl AsRef<[P]>) -> Self
where
P: Fn(&T) -> bool;
}
impl<'t, T: Debug, M: Mode> VecAssertions<'t, T> for AssertThat<'t, Vec<T>, M> {
#[track_caller]
fn contains<E>(self, expected: E) -> Self
where
E: Debug,
T: AssertrPartialEq<E> + Debug,
{
self.derive(Vec::as_slice).contains(expected);
self
}
#[track_caller]
fn contains_exactly<E>(self, expected: impl AsRef<[E]>) -> Self
where
E: Debug + 't,
T: AssertrPartialEq<E> + Debug,
{
self.derive(Vec::as_slice).contains_exactly(expected);
self
}
#[track_caller]
fn contains_exactly_in_any_order<E: AsRef<[T]>>(self, expected: E) -> Self
where
T: PartialEq + Debug,
{
self.derive(Vec::as_slice)
.contains_exactly_in_any_order(expected);
self
}
#[track_caller]
fn contains_exactly_matching_in_any_order<P>(self, expected: impl AsRef<[P]>) -> Self
where
P: Fn(&T) -> bool, {
self.derive(Vec::as_slice)
.contains_exactly_matching_in_any_order(expected);
self
}
}
#[cfg(test)]
mod tests {
mod contains {
use crate::prelude::*;
use indoc::formatdoc;
#[test]
fn succeeds_when_expected_is_contained() {
assert_that!(vec![1, 2, 3]).contains(1);
assert_that!(vec![1, 2, 3]).contains(2);
assert_that!(vec![1, 2, 3]).contains(3);
}
#[test]
fn compiles_for_comparable_but_different_type() {
assert_that!(vec!["foo"]).contains("foo".to_owned());
assert_that!(vec!["foo".to_owned()]).contains("foo");
}
#[test]
fn panics_when_expected_is_not_contained() {
assert_that_panic_by(|| {
assert_that!(vec![1, 2, 3]).with_location(false).contains(4);
})
.has_type::<String>()
.is_equal_to(formatdoc! {"
-------- assertr --------
Actual: [
1,
2,
3,
]
does not contain expected: 4
-------- assertr --------
"});
}
}
mod contains_exactly {
use crate::prelude::*;
use indoc::formatdoc;
#[test]
fn succeeds_when_exact_match() {
assert_that!(vec![1, 2, 3]).contains_exactly([1, 2, 3]);
}
#[test]
fn compiles_for_different_type_combinations() {
assert_that!(vec!["foo".to_owned()]).contains_exactly(["foo"]);
assert_that!(vec!["foo"]).contains_exactly(["foo".to_owned()]);
assert_that!(vec!["foo"]).contains_exactly(["foo"]);
assert_that!(vec!["foo"]).contains_exactly(vec!["foo".to_owned()]);
assert_that!(vec!["foo"]).contains_exactly(vec!["foo".to_owned()].into_iter());
assert_that!(vec!["foo"]).contains_exactly(vec!["foo".to_owned()].as_slice());
}
#[test]
fn panics_when_not_exact_match() {
assert_that_panic_by(|| {
assert_that!(vec![1, 2, 3])
.with_location(false)
.contains_exactly([2, 3, 4]);
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Actual: [
1,
2,
3,
],
did not exactly match
Expected: [
2,
3,
4,
]
Details: [
Elements not expected: [
1,
],
Elements not found: [
4,
],
]
-------- assertr --------
"#});
}
#[test]
fn panics_with_detail_message_when_only_differing_in_order() {
assert_that_panic_by(|| {
assert_that!(vec![1, 2, 3])
.with_location(false)
.contains_exactly([3, 2, 1]);
})
.has_type::<String>()
.is_equal_to(formatdoc! {r#"
-------- assertr --------
Actual: [
1,
2,
3,
],
did not exactly match
Expected: [
3,
2,
1,
]
Details: [
The order of elements does not match!,
]
-------- assertr --------
"#});
}
}
mod contains_exactly_in_any_order {
use crate::prelude::*;
use indoc::formatdoc;
#[test]
fn succeeds_when_values_match() {
assert_that!(vec![1, 2, 3]).contains_exactly_in_any_order([2, 3, 1]);
}
#[test]
fn panics_when_value_is_missing() {
assert_that_panic_by(|| {
assert_that!(vec![1, 2, 3])
.with_location(false)
.contains_exactly_in_any_order([2, 3, 4]);
})
.has_type::<String>()
.is_equal_to(formatdoc! {"
-------- assertr --------
Actual: [
1,
2,
3,
],
Elements expected: [
2,
3,
4,
]
Elements not found: [
4,
]
Elements not expected: [
1,
]
-------- assertr --------
"});
}
}
mod contains_exactly_matching_in_any_order {
use crate::prelude::*;
use indoc::formatdoc;
#[test]
fn succeeds_when_predicates_match() {
assert_that!(vec![1, 2, 3]).contains_exactly_matching_in_any_order(
[
move |it: &i32| *it == 1,
move |it: &i32| *it == 2,
move |it: &i32| *it == 3,
]
.as_slice(),
);
}
#[test]
fn succeeds_when_predicates_match_in_different_order() {
assert_that!(vec![1, 2, 3]).contains_exactly_matching_in_any_order(
[
move |it: &i32| *it == 3,
move |it: &i32| *it == 1,
move |it: &i32| *it == 2,
]
.as_slice(),
);
}
#[test]
fn panics_when_data_is_unmatched() {
assert_that_panic_by(|| {
assert_that!(vec![1, 2, 3])
.with_location(false)
.contains_exactly_matching_in_any_order(
[
move |it: &i32| *it == 2,
move |it: &i32| *it == 3,
move |it: &i32| *it == 4,
]
.as_slice(),
);
})
.has_type::<String>()
.is_equal_to(formatdoc! {"
-------- assertr --------
Actual: [
1,
2,
3,
],
did not exactly match predicates in any order.
Details: [
Elements not matched: [
1,
],
]
-------- assertr --------
"});
}
}
}