use core::{marker::PhantomData, ops::RangeBounds};
pub fn in_range<RangeT: RangeBounds<ExpectedT>, ExpectedT>(
range: RangeT,
) -> __internal::InRangeMatcher<RangeT, ExpectedT> {
__internal::InRangeMatcher(range, PhantomData)
}
#[doc(hidden)]
mod __internal {
use crate::matcher::{Describable, Matcher, MatcherResult};
use core::{fmt::Debug, marker::PhantomData, ops::RangeBounds};
pub struct InRangeMatcher<RangeT, ExpectedT>(
pub(super) RangeT,
pub(super) PhantomData<ExpectedT>,
);
impl<
ExpectedT: Debug + PartialOrd<ActualT>,
ActualT: Debug + PartialOrd<ExpectedT> + ?Sized,
RangeT: RangeBounds<ExpectedT> + Debug,
> Matcher<ActualT> for InRangeMatcher<RangeT, ExpectedT>
{
fn matches(&self, actual: &ActualT) -> MatcherResult {
self.0.contains(actual).into()
}
}
impl<RangeT: Debug, ExpectedT> Describable for InRangeMatcher<RangeT, ExpectedT> {
fn describe(&self, matcher_result: MatcherResult) -> crate::description::Description {
match matcher_result {
MatcherResult::Match => {
format!("which is contained in the range {:?}", self.0).into()
}
MatcherResult::NoMatch => {
format!("which is not contained in the range {:?}", self.0).into()
}
}
}
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn matches_within_interval() -> TestResult<()> {
verify_that!(10, in_range(0..20))
}
#[test]
fn does_not_match_outside_interval() -> TestResult<()> {
verify_that!(10, not(in_range(0..10)))
}
#[test]
fn matches_at_bound_of_closed_interval() -> TestResult<()> {
verify_that!(10, in_range(0..=10))
}
#[test]
fn shows_correct_description_when_not_matched() -> TestResult<()> {
let result = verify_that!(10, in_range(0..10));
verify_that!(
result,
err(displays_as(contains_substring("which is contained in the range 0..10")))
)
}
#[test]
fn shows_correct_description_when_matched() -> TestResult<()> {
let result = verify_that!(10, not(in_range(0..=10)));
verify_that!(
result,
err(displays_as(contains_substring("which is not contained in the range 0..=10")))
)
}
}