kernal/collections/
ord.rs

1//! Contains assertions for [Collection]s whose items implement the [Ord] trait in addition to
2//! [Debug]. See [CollectionOrdAssertions] for more details.
3
4use std::borrow::Borrow;
5use std::fmt::Debug;
6
7use crate::{AssertThat, Failure};
8use crate::collections::{Collection, CollectionDebug, HighlightedCollectionDebug};
9
10/// An extension trait to be used on the output of [assert_that](crate::assert_that) with an
11/// argument that implements the [Collection] trait and whose [Collection::Item] type implements
12/// [Ord] in addition to [Debug].
13///
14/// Examples:
15///
16/// ```
17/// use kernal::prelude::*;
18///
19/// assert_that!([3, 1, 4, 1]).has_maximum(4).does_not_have_minimum(0);
20/// ```
21pub trait CollectionOrdAssertions<'collection, C: Collection<'collection>> {
22
23    /// Asserts that the tested collection contains an item equal to `max` according to [PartialEq]
24    /// and that all other items are less than or equal to that value according to [Ord].
25    fn has_maximum<M: Borrow<C::Item>>(self, max: M) -> Self;
26
27    /// Asserts that the tested collection does not contain an item equal to `max` according to
28    /// [PartialEq] or that some item is greater than that value according to [Ord].
29    fn does_not_have_maximum<M: Borrow<C::Item>>(self, max: M) -> Self;
30
31    /// Asserts that the tested collection contains an item equal to `min` according to [PartialEq]
32    /// and that all other items are greater than or equal to that value according to [Ord].
33    fn has_minimum<M: Borrow<C::Item>>(self, min: M) -> Self;
34
35    /// Asserts that the tested collection does not contain an item equal to `min` according to
36    /// [PartialEq] or that some item is less than that value according to [Ord].
37    fn does_not_have_minimum<M: Borrow<C::Item>>(self, min: M) -> Self;
38}
39
40fn verify_has_extreme<'collection, C, M>(assert_that: &AssertThat<C>, expected_extreme: M,
41    actual_extreme: Option<&C::Item>, extreme_name: &str)
42where
43    C: Collection<'collection>,
44    C::Item: Debug + Ord,
45    M: Borrow<C::Item>
46{
47    let expected_extreme = expected_extreme.borrow();
48    let failure = Failure::new(assert_that)
49        .expected_it(format!("to have the {} <{:?}>", extreme_name, expected_extreme));
50
51    match actual_extreme {
52        Some(extreme) if extreme == expected_extreme => { }
53        Some(extreme) => {
54            let collection_debug = CollectionDebug { collection: &assert_that.data };
55
56            failure
57                .but_it(format!(
58                    "was <{:?}>, which has the {} <{:?}>", collection_debug, extreme_name, extreme))
59                .fail()
60        }
61        None => failure.but_it("was empty").fail()
62    }
63}
64
65fn verify_does_not_have_extreme<'collection, C, M>(assert_that: &AssertThat<C>,
66    unexpected_extreme: M, actual_extreme: Option<&C::Item>, extreme_name: &str)
67where
68    C: Collection<'collection>,
69    C::Item: Debug + Ord,
70    M: Borrow<C::Item>
71{
72    let unexpected_extreme = unexpected_extreme.borrow();
73
74    if actual_extreme == Some(unexpected_extreme) {
75        let actual_extreme = actual_extreme.unwrap();
76        let actual_extreme_index = assert_that.data.iterator().enumerate()
77            .find(|&(_, item)| item == actual_extreme)
78            .map(|(index, _)| index)
79            .unwrap();
80        let highlighted_collection_debug =
81            HighlightedCollectionDebug::with_single_highlighted_element(
82                &assert_that.data, actual_extreme_index);
83
84        Failure::new(assert_that)
85            .expected_it(format!("not to have the {} <{:?}>", extreme_name, unexpected_extreme))
86            .but_it(format!("was <{:?}>", highlighted_collection_debug))
87            .fail()
88    }
89}
90
91impl<'collection, C> CollectionOrdAssertions<'collection, C> for AssertThat<C>
92where
93    C: Collection<'collection>,
94    C::Item: Debug + Ord
95{
96    fn has_maximum<M: Borrow<C::Item>>(self, max: M) -> Self {
97        verify_has_extreme(&self, max, self.data.iterator().max(), "maximum");
98
99        self
100    }
101
102    fn does_not_have_maximum<M: Borrow<C::Item>>(self, max: M) -> Self {
103        verify_does_not_have_extreme(&self, max, self.data.iterator().max(), "maximum");
104
105        self
106    }
107
108    fn has_minimum<M: Borrow<C::Item>>(self, min: M) -> Self {
109        verify_has_extreme(&self, min, self.data.iterator().min(), "minimum");
110
111        self
112    }
113
114    fn does_not_have_minimum<M: Borrow<C::Item>>(self, min: M) -> Self {
115        verify_does_not_have_extreme(&self, min, self.data.iterator().min(), "minimum");
116
117        self
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use crate::{assert_fails, assert_that};
124
125    use super::*;
126
127    #[test]
128    fn has_maximum_passes_for_correct_maximum() {
129        assert_that!(&[5, 1, 6, 2]).has_maximum(6);
130    }
131
132    #[test]
133    fn has_maximum_fails_for_empty_collection() {
134        assert_fails!((&[] as &[i32]).has_maximum(0),
135            expected it "to have the maximum <0>"
136            but it "was empty");
137    }
138
139    #[test]
140    fn has_maximum_fails_for_lower_maximum() {
141        assert_fails!((&[3, 1, 4, 2]).has_maximum(5),
142            expected it "to have the maximum <5>"
143            but it "was <[ 3, 1, 4, 2 ]>, which has the maximum <4>");
144    }
145
146    #[test]
147    fn has_maximum_fails_for_higher_maximum() {
148        assert_fails!((&[5, 7, 4, 1]).has_maximum(5),
149            expected it "to have the maximum <5>"
150            but it "was <[ 5, 7, 4, 1 ]>, which has the maximum <7>");
151    }
152
153    #[test]
154    fn does_not_have_maximum_passes_for_empty_collection() {
155        assert_that!(&[] as &[i32]).does_not_have_maximum(0);
156    }
157
158    #[test]
159    fn does_not_have_maximum_passes_for_lower_maximum() {
160        assert_that!(&[3, 1, 4, 2]).does_not_have_maximum(5);
161    }
162
163    #[test]
164    fn does_not_have_maximum_passes_for_higher_maximum() {
165        assert_that!(&[5, 7, 4, 1]).does_not_have_maximum(5);
166    }
167
168    #[test]
169    fn does_not_have_maximum_fails_for_correct_maximum() {
170        assert_fails!((&[5, 1, 6, 2]).does_not_have_maximum(6),
171            expected it "not to have the maximum <6>"
172            but it "was <[ 5, 1, [6], 2 ]>");
173    }
174
175    #[test]
176    fn has_minimum_passes_for_correct_minimum() {
177        assert_that!(&[5, 1, 6, 2]).has_minimum(1);
178    }
179
180    #[test]
181    fn has_minimum_fails_for_empty_collection() {
182        assert_fails!((&[] as &[i32]).has_minimum(0),
183            expected it "to have the minimum <0>"
184            but it "was empty");
185    }
186
187    #[test]
188    fn has_minimum_fails_for_higher_minimum() {
189        assert_fails!((&[3, 1, 4, 2]).has_minimum(0),
190            expected it "to have the minimum <0>"
191            but it "was <[ 3, 1, 4, 2 ]>, which has the minimum <1>");
192    }
193
194    #[test]
195    fn has_minimum_fails_for_lower_minimum() {
196        assert_fails!((&[5, 7, 4, 1]).has_minimum(4),
197            expected it "to have the minimum <4>"
198            but it "was <[ 5, 7, 4, 1 ]>, which has the minimum <1>");
199    }
200
201    #[test]
202    fn does_not_have_minimum_passes_for_empty_collection() {
203        assert_that!(&[] as &[i32]).does_not_have_minimum(0);
204    }
205
206    #[test]
207    fn does_not_have_minimum_passes_for_higher_minimum() {
208        assert_that!(&[3, 1, 4, 2]).does_not_have_minimum(0);
209    }
210
211    #[test]
212    fn does_not_have_minimum_passes_for_lower_minimum() {
213        assert_that!(&[5, 7, 4, 1]).does_not_have_minimum(4);
214    }
215
216    #[test]
217    fn does_not_have_minimum_fails_for_correct_minimum() {
218        assert_fails!((&[5, 1, 6, 2]).does_not_have_minimum(1),
219            expected it "not to have the minimum <1>"
220            but it "was <[ 5, [1], 6, 2 ]>");
221    }
222}