asserting/range/
mod.rs

1//! Implementation of assertions for `Range` and `RangeInclusive` values.
2
3use crate::assertions::AssertInRange;
4use crate::colored::{mark_missing, mark_missing_substr, mark_unexpected};
5use crate::expectations::{IsInRange, IsNotInRange};
6use crate::properties::IsEmptyProperty;
7use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Spec};
8use crate::std::fmt::Debug;
9use crate::std::format;
10use crate::std::ops::{Bound, Range, RangeBounds, RangeInclusive};
11use crate::std::string::String;
12
13impl<T> IsEmptyProperty for Range<T>
14where
15    T: PartialEq,
16{
17    fn is_empty_property(&self) -> bool {
18        self.start == self.end
19    }
20}
21
22impl<T> IsEmptyProperty for RangeInclusive<T>
23where
24    T: PartialOrd,
25{
26    fn is_empty_property(&self) -> bool {
27        self.start() > self.end()
28    }
29}
30
31impl<S, E, R> AssertInRange<E> for Spec<'_, S, R>
32where
33    S: PartialOrd<E> + Debug,
34    E: PartialOrd<S> + Debug,
35    R: FailingStrategy,
36{
37    fn is_in_range<U>(self, range: U) -> Self
38    where
39        U: RangeBounds<E> + Debug,
40    {
41        self.expecting(IsInRange::new(range))
42    }
43
44    fn is_not_in_range<U>(self, range: U) -> Self
45    where
46        U: RangeBounds<E> + Debug,
47    {
48        self.expecting(IsNotInRange::new(range))
49    }
50}
51
52impl<S, E, R> Expectation<S> for IsInRange<R, E>
53where
54    S: PartialOrd<E> + Debug,
55    E: PartialOrd<S> + Debug,
56    R: RangeBounds<E> + Debug,
57{
58    fn test(&mut self, subject: &S) -> bool {
59        self.expected_range.contains(subject)
60    }
61
62    fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
63        let marked_actual = mark_unexpected(actual, format);
64        let marked_expected_start = match self.expected_range.start_bound() {
65            Bound::Included(start) => {
66                if actual < start {
67                    format!("{} <=", mark_missing(start, format))
68                } else {
69                    format!("{start:?} <=")
70                }
71            },
72            Bound::Excluded(start) => {
73                if actual <= start {
74                    format!("{} <", mark_missing(start, format))
75                } else {
76                    format!("{start:?} <")
77                }
78            },
79            Bound::Unbounded => format!("{} <", mark_missing_substr("..", format)),
80        };
81        let marked_expected_end = match self.expected_range.end_bound() {
82            Bound::Included(end) => {
83                if actual > end {
84                    format!("<= {}", mark_missing(end, format))
85                } else {
86                    format!("<= {end:?}")
87                }
88            },
89            Bound::Excluded(end) => {
90                if actual >= end {
91                    format!("< {}", mark_missing(end, format))
92                } else {
93                    format!("< {end:?}")
94                }
95            },
96            Bound::Unbounded => format!("< {}", mark_missing_substr("..", format)),
97        };
98        format!(
99            "expected {expression} is within range of {:?}\n   but was: {marked_actual}\n  expected: {marked_expected_start} x {marked_expected_end}",
100            self.expected_range,
101        )
102    }
103}
104
105impl<S, E, R> Expectation<S> for IsNotInRange<R, E>
106where
107    S: PartialOrd<E> + Debug,
108    E: PartialOrd<S> + Debug,
109    R: RangeBounds<E> + Debug,
110{
111    fn test(&mut self, subject: &S) -> bool {
112        !self.expected_range.contains(subject)
113    }
114
115    fn message(&self, expression: Expression<'_>, actual: &S, format: &DiffFormat) -> String {
116        let marked_actual = mark_unexpected(actual, format);
117        let marked_expected_start = match self.expected_range.start_bound() {
118            Bound::Included(start) => format!("< {}", mark_missing(start, format)),
119            Bound::Excluded(start) => format!("<= {}", mark_missing(start, format)),
120            Bound::Unbounded => format!("< {}", mark_missing_substr("..", format)),
121        };
122        let marked_expected_end = match self.expected_range.end_bound() {
123            Bound::Included(end) => format!("> {}", mark_missing(end, format)),
124            Bound::Excluded(end) => format!(">= {}", mark_missing(end, format)),
125            Bound::Unbounded => format!("> {}", mark_missing_substr("..", format)),
126        };
127        format!(
128            "expected {expression} is not within range of {:?}\n   but was: {marked_actual}\n  expected: x {marked_expected_start} || x {marked_expected_end}",
129            self.expected_range,
130        )
131    }
132}
133
134#[cfg(test)]
135mod tests;