use crate::matcher::Matcher;
pub fn len<E: Matcher<usize>>(expected: E) -> __internal::LenMatcher<E> {
__internal::LenMatcher { expected }
}
pub mod __internal {
use crate::description::Description;
use crate::matcher::{Describable, Matcher, MatcherResult};
use crate::matcher_support::count_elements::count_elements;
use core::fmt::Debug;
#[doc(hidden)]
pub struct LenMatcher<E> {
pub(super) expected: E,
}
impl<T: Debug + ?Sized, E: Matcher<usize>> Matcher<T> for LenMatcher<E>
where
for<'a> &'a T: IntoIterator,
{
fn matches(&self, actual: &T) -> MatcherResult {
self.expected.matches(&count_elements(actual))
}
fn explain_match(&self, actual: &T) -> Description {
let actual_size = count_elements(actual);
format!(
"which has length {}, {}",
actual_size,
self.expected.explain_match(&actual_size)
)
.into()
}
}
impl<E: Describable> Describable for LenMatcher<E> {
fn describe(&self, matcher_result: MatcherResult) -> Description {
match matcher_result {
MatcherResult::Match => {
format!("has length, which {}", self.expected.describe(MatcherResult::Match))
.into()
}
MatcherResult::NoMatch => {
format!("has length, which {}", self.expected.describe(MatcherResult::NoMatch))
.into()
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::len;
use crate::description::Description;
use crate::matcher::{Describable, Matcher, MatcherResult};
use crate::prelude::*;
use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
use alloc::vec::Vec;
use core::fmt::Debug;
use core::marker::PhantomData;
use indoc::indoc;
#[test]
fn len_matcher_matches_vec() -> TestResult<()> {
verify_that!(vec![1, 2, 3], len(eq(3)))
}
#[test]
fn len_matcher_matches_array_reference_with_deref_notation() -> TestResult<()> {
let value = &[1, 2, 3];
verify_that!(*value, len(eq(3)))
}
#[test]
fn len_matcher_matches_array_reference_points_to() -> TestResult<()> {
verify_that!(&[1, 2, 3], points_to(len(eq(3))))
}
#[test]
fn len_matcher_matches_slice_of_array() -> TestResult<()> {
let value = &[1, 2, 3];
verify_that!(value[0..1], len(eq(1)))
}
#[test]
fn len_matcher_matches_slice_of_vec() -> TestResult<()> {
let value = vec![1, 2, 3];
let slice = value.as_slice();
verify_that!(*slice, len(eq(3)))
}
#[test]
fn len_matcher_matches_array() -> TestResult<()> {
verify_that!([1, 2, 3], len(eq(3)))
}
#[test]
fn len_matcher_matches_btreemap() -> TestResult<()> {
let value = BTreeMap::from([(1, 2), (2, 3), (3, 4)]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_matches_btreeset() -> TestResult<()> {
let value = BTreeSet::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_matches_binaryheap() -> TestResult<()> {
let value = BinaryHeap::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[cfg(feature = "std")]
#[test]
fn len_matcher_matches_hashmap() -> TestResult<()> {
use std::collections::HashMap;
let value = HashMap::from([(1, 2), (2, 3), (3, 4)]);
verify_that!(value, len(eq(3)))
}
#[cfg(feature = "std")]
#[test]
fn len_matcher_matches_hashset() -> TestResult<()> {
use std::collections::HashSet;
let value = HashSet::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_matches_linkedlist() -> TestResult<()> {
let value = LinkedList::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_matches_vecdeque() -> TestResult<()> {
let value = VecDeque::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[derive(Debug)]
struct OwnedItemContainer(Vec<i32>);
impl<'a> IntoIterator for &'a OwnedItemContainer {
type Item = i32;
type IntoIter = core::iter::Copied<core::slice::Iter<'a, i32>>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter().copied()
}
}
#[test]
fn len_matches_on_container_when_ref_to_container_has_into_iterator_producing_owned_values()
-> TestResult<()> {
verify_that!(OwnedItemContainer(vec![1, 2, 3]), len(eq(3)))
}
#[test]
fn len_matcher_explain_match() -> TestResult<()> {
struct TestMatcher<T>(PhantomData<T>);
impl<T: Debug> Matcher<T> for TestMatcher<T> {
fn matches(&self, _: &T) -> MatcherResult {
false.into()
}
fn explain_match(&self, _: &T) -> Description {
"called explain_match".into()
}
}
impl<T> Describable for TestMatcher<T> {
fn describe(&self, _: MatcherResult) -> Description {
"called described".into()
}
}
verify_that!(
len(TestMatcher(Default::default())).explain_match(&[1, 2, 3]),
displays_as(eq("which has length 3, called explain_match"))
)
}
#[test]
fn len_matcher_error_message() -> TestResult<()> {
let result = verify_that!(vec![1, 2, 3, 4], len(eq(3)));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Value of: vec![1, 2, 3, 4]
Expected: has length, which is equal to 3
Actual: [1, 2, 3, 4],
which has length 4, which isn't equal to 3"
))))
)
}
}