1use crate::assertions::AssertInRange;
4use crate::colored::{mark_missing, mark_missing_string, mark_unexpected};
5use crate::expectations::{is_in_range, not, IsInRange};
6use crate::properties::IsEmptyProperty;
7use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Invertible, 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(is_in_range(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(not(is_in_range(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(
63 &self,
64 expression: &Expression<'_>,
65 actual: &S,
66 inverted: bool,
67 format: &DiffFormat,
68 ) -> String {
69 let marked_actual = mark_unexpected(actual, format);
70 let (not, marked_expected) = if inverted {
71 let marked_expected_start = match self.expected_range.start_bound() {
72 Bound::Included(start) => format!("< {}", mark_missing(start, format)),
73 Bound::Excluded(start) => format!("<= {}", mark_missing(start, format)),
74 Bound::Unbounded => format!("< {}", mark_missing_string("..", format)),
75 };
76 let marked_expected_end = match self.expected_range.end_bound() {
77 Bound::Included(end) => format!("> {}", mark_missing(end, format)),
78 Bound::Excluded(end) => format!(">= {}", mark_missing(end, format)),
79 Bound::Unbounded => format!("> {}", mark_missing_string("..", format)),
80 };
81
82 (
83 "not ",
84 format!("x {marked_expected_start} || x {marked_expected_end}"),
85 )
86 } else {
87 let marked_expected_start = match self.expected_range.start_bound() {
88 Bound::Included(start) => {
89 if actual < start {
90 format!("{} <=", mark_missing(start, format))
91 } else {
92 format!("{start:?} <=")
93 }
94 },
95 Bound::Excluded(start) => {
96 if actual <= start {
97 format!("{} <", mark_missing(start, format))
98 } else {
99 format!("{start:?} <")
100 }
101 },
102 Bound::Unbounded => format!("{} <", mark_missing_string("..", format)),
103 };
104 let marked_expected_end = match self.expected_range.end_bound() {
105 Bound::Included(end) => {
106 if actual > end {
107 format!("<= {}", mark_missing(end, format))
108 } else {
109 format!("<= {end:?}")
110 }
111 },
112 Bound::Excluded(end) => {
113 if actual >= end {
114 format!("< {}", mark_missing(end, format))
115 } else {
116 format!("< {end:?}")
117 }
118 },
119 Bound::Unbounded => format!("< {}", mark_missing_string("..", format)),
120 };
121
122 (
123 "",
124 format!("{marked_expected_start} x {marked_expected_end}"),
125 )
126 };
127
128 format!(
129 "expected {expression} to be {not}within range of {:?}\n but was: {marked_actual}\n expected: {marked_expected}",
130 self.expected_range,
131 )
132 }
133}
134
135impl<R, E> Invertible for IsInRange<R, E> {}
136
137#[cfg(test)]
138mod tests;