Skip to main content

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