monkey_test/shrink/
zip.rs

1use crate::BoxShrink;
2
3/// Combine two shrinkers together element wise into shrinker of tuples.
4///
5/// ```rust
6/// use monkey_test::*;
7///
8/// let alfa1: BoxShrink<u8> = shrink::int::<u8>();
9/// let beta1: BoxShrink<i64> = shrink::int::<i64>();
10///
11/// let alfa2: BoxShrink<u8> = shrink::int::<u8>();
12/// let beta2: BoxShrink<i64> = shrink::int::<i64>();
13///
14///
15/// // Zip two shrinkers to a tuple shrinker.
16/// let tuples1: BoxShrink<(u8, i64)> = shrink::zip(alfa1, beta1);
17///
18/// // Shorthand way to do the same thing.
19/// let tuples2: BoxShrink<(u8, i64)> = alfa2.zip(beta2);
20/// ```
21pub fn zip<E0, E1>(
22    shrink0: BoxShrink<E0>,
23    shrink1: BoxShrink<E1>,
24) -> BoxShrink<(E0, E1)>
25where
26    E0: Clone + 'static,
27    E1: Clone + 'static,
28{
29    crate::shrink::from_fn(move |original: (E0, E1)| {
30        let o0 = original.0.clone();
31        let o1 = original.1.clone();
32
33        let it_left = shrink0
34            .candidates(original.0.clone())
35            .map(move |item0| (item0, o1.clone()));
36
37        let it_right = shrink1
38            .candidates(original.1.clone())
39            .map(move |item1| (o0.clone(), item1));
40
41        let it_both = shrink0
42            .candidates(original.0.clone())
43            .zip(shrink1.candidates(original.1.clone()));
44
45        it_left.chain(it_right).chain(it_both)
46    })
47}
48
49#[cfg(test)]
50mod test {
51    use crate::shrink::int_to_zero;
52    use crate::shrink::none;
53    use crate::testing::assert_shrinker_has_at_least_these_candidates;
54    use crate::BoxShrink;
55
56    #[test]
57    fn no_shrinking_if_no_element_shrinkers() {
58        let shrink: BoxShrink<(u8, char)> =
59            super::zip(none::<u8>(), none::<char>());
60
61        let actual_length = shrink.candidates((100, 'x')).take(1000).count();
62
63        assert_eq!(actual_length, 0)
64    }
65
66    /// The combination of candidates are not complete, but is good enough as
67    /// initial behaviour.
68    #[test]
69    fn returns_permutations_of_inner_candidates() {
70        let shrink: BoxShrink<(u8, u8)> =
71            super::zip(int_to_zero(), int_to_zero());
72
73        assert_shrinker_has_at_least_these_candidates(
74            shrink,
75            (4, 4),
76            &[
77                (4, 3),
78                (4, 2),
79                (4, 1),
80                (4, 0),
81                (3, 4),
82                (2, 4),
83                (1, 4),
84                (0, 4),
85                (3, 3),
86                (2, 2),
87                (1, 1),
88                (0, 0),
89            ],
90        );
91    }
92}