use crate::description::Description;
use crate::matcher::{Matcher, MatcherBase, MatcherResult};
use crate::matcher_support::count_elements::count_elements;
use std::fmt::Debug;
pub fn len<E>(expected: E) -> LenMatcher<E> {
LenMatcher { expected }
}
#[derive(MatcherBase)]
pub struct LenMatcher<E> {
expected: E,
}
impl<T: Debug + Copy, E: Matcher<usize>> Matcher<T> for LenMatcher<E>
where
T: IntoIterator,
{
fn matches(&self, actual: T) -> MatcherResult {
self.expected.matches(count_elements(actual))
}
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()
}
}
}
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()
}
}
#[cfg(test)]
mod tests {
use crate::description::Description;
use crate::matcher::MatcherResult;
use crate::prelude::*;
use indoc::indoc;
use std::collections::{
BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque,
};
use std::fmt::Debug;
#[test]
fn len_matcher_match_vec() -> Result<()> {
let value = vec![1, 2, 3];
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_array_reference() -> Result<()> {
let value = &[1, 2, 3];
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_slice_of_array() -> Result<()> {
let value = &[1, 2, 3];
verify_that!(value[0..1], len(eq(1)))
}
#[test]
fn len_matcher_match_slice_of_vec() -> Result<()> {
let value = vec![1, 2, 3];
let slice = value.as_slice();
verify_that!(slice, len(eq(3)))
}
#[test]
fn len_matcher_match_sized_slice() -> Result<()> {
let value = [1, 2, 3];
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_btreemap() -> Result<()> {
let value = BTreeMap::from([(1, 2), (2, 3), (3, 4)]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_btreeset() -> Result<()> {
let value = BTreeSet::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_binaryheap() -> Result<()> {
let value = BinaryHeap::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_hashmap() -> Result<()> {
let value = HashMap::from([(1, 2), (2, 3), (3, 4)]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_hashset() -> Result<()> {
let value = HashSet::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_linkedlist() -> Result<()> {
let value = LinkedList::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_match_vecdeque() -> Result<()> {
let value = VecDeque::from([1, 2, 3]);
verify_that!(value, len(eq(3)))
}
#[test]
fn len_matcher_explain_match() -> Result<()> {
#[derive(MatcherBase)]
struct TestMatcher;
impl<T: Debug + Copy> Matcher<T> for TestMatcher {
fn matches(&self, _: T) -> MatcherResult {
false.into()
}
fn describe(&self, _: MatcherResult) -> Description {
"called described".into()
}
fn explain_match(&self, _: T) -> Description {
"called explain_match".into()
}
}
verify_that!(
len(TestMatcher).explain_match([1, 2, 3]),
displays_as(eq("which has length 3, called explain_match"))
)
}
#[test]
fn len_matcher_error_message() -> Result<()> {
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"
))))
)
}
}