1use 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;