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