mry 0.7.1

A simple but powerful mocking library that supports struct, trait, and function.
Documentation
use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo};

#[doc(hidden)]
#[derive(Debug)]
pub enum Times {
    Exact(usize),
    Range((Bound<usize>, Bound<usize>)),
}

impl Times {
    pub(crate) fn contains(&self, count: &usize) -> bool {
        match self {
            Times::Exact(n) => count == n,
            Times::Range(range) => range.contains(count),
        }
    }
}

impl From<usize> for Times {
    fn from(times: usize) -> Self {
        Times::Exact(times)
    }
}

impl From<Range<usize>> for Times {
    fn from(range: Range<usize>) -> Self {
        Times::Range((range.start_bound().cloned(), range.end_bound().cloned()))
    }
}

impl From<RangeFrom<usize>> for Times {
    fn from(range: RangeFrom<usize>) -> Self {
        Times::Range((range.start_bound().cloned(), range.end_bound().cloned()))
    }
}

impl From<RangeTo<usize>> for Times {
    fn from(range: RangeTo<usize>) -> Self {
        Times::Range((range.start_bound().cloned(), range.end_bound().cloned()))
    }
}

impl From<RangeInclusive<usize>> for Times {
    fn from(range: RangeInclusive<usize>) -> Self {
        Times::Range((range.start_bound().cloned(), range.end_bound().cloned()))
    }
}

use std::fmt;

impl fmt::Display for Times {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Times::Exact(n) => write!(f, "{}", n),
            Times::Range((start, end)) => {
                let start = match start {
                    Bound::Included(n) => format!("{}<=", n),
                    Bound::Excluded(n) => format!("{}<", n),
                    Bound::Unbounded => String::from(""),
                };
                let end = match end {
                    Bound::Included(n) => format!("<={}", n),
                    Bound::Excluded(n) => format!("<{}", n),
                    Bound::Unbounded => String::from(""),
                };
                write!(f, "{}x{}", start, end)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn exact() {
        let times = Times::Exact(2);
        assert!(times.contains(&2));
        assert!(!times.contains(&1));
        assert!(!times.contains(&3));
    }

    #[test]
    fn range() {
        let times = Times::Range((Bound::Included(2), Bound::Excluded(4)));
        assert!(!times.contains(&1));
        assert!(times.contains(&2));
        assert!(times.contains(&3));
        assert!(!times.contains(&4));
        assert!(!times.contains(&5));
    }

    #[test]
    fn display() {
        assert_eq!(Times::from(2).to_string(), "2");
        assert_eq!(Times::from(1..2).to_string(), "1<=x<2");
        assert_eq!(Times::from(1..=2).to_string(), "1<=x<=2");
        assert_eq!(Times::from(1..).to_string(), "1<=x");
        assert_eq!(Times::from(..2).to_string(), "x<2");
    }
}