proptest/strategy/
map.rs

1//-
2// Copyright 2017 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use crate::std_facade::Arc;
11use core::fmt;
12use core::marker::PhantomData;
13
14use crate::strategy::traits::*;
15use crate::test_runner::*;
16
17//==============================================================================
18// Map
19//==============================================================================
20
21/// `Strategy` and `ValueTree` map adaptor.
22///
23/// See `Strategy::prop_map()`.
24#[must_use = "strategies do nothing unless used"]
25pub struct Map<S, F> {
26    pub(super) source: S,
27    pub(super) fun: Arc<F>,
28}
29
30impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        f.debug_struct("Map")
33            .field("source", &self.source)
34            .field("fun", &"<function>")
35            .finish()
36    }
37}
38
39impl<S: Clone, F> Clone for Map<S, F> {
40    fn clone(&self) -> Self {
41        Map {
42            source: self.source.clone(),
43            fun: Arc::clone(&self.fun),
44        }
45    }
46}
47
48impl<S: Strategy, O: fmt::Debug, F: Fn(S::Value) -> O> Strategy for Map<S, F> {
49    type Tree = Map<S::Tree, F>;
50    type Value = O;
51
52    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
53        self.source.new_tree(runner).map(|v| Map {
54            source: v,
55            fun: Arc::clone(&self.fun),
56        })
57    }
58}
59
60impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value) -> O> ValueTree
61    for Map<S, F>
62{
63    type Value = O;
64
65    fn current(&self) -> O {
66        (self.fun)(self.source.current())
67    }
68
69    fn simplify(&mut self) -> bool {
70        self.source.simplify()
71    }
72
73    fn complicate(&mut self) -> bool {
74        self.source.complicate()
75    }
76}
77
78//==============================================================================
79// MapInto
80//==============================================================================
81
82// NOTE: Since this is external stable API,
83// we avoid relying on the Map in `statics`.
84
85/// `Strategy` and `ValueTree` map into adaptor.
86///
87/// See `Strategy::prop_map_into()`.
88#[must_use = "strategies do nothing unless used"]
89pub struct MapInto<S, O> {
90    pub(super) source: S,
91    pub(super) output: PhantomData<O>,
92}
93
94impl<S, O> MapInto<S, O> {
95    /// Construct a `MapInto` mapper from an `S` strategy into a strategy
96    /// producing `O`s.
97    pub(super) fn new(source: S) -> Self {
98        Self {
99            source,
100            output: PhantomData,
101        }
102    }
103}
104
105impl<S: fmt::Debug, O> fmt::Debug for MapInto<S, O> {
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        f.debug_struct("MapInto")
108            .field("source", &self.source)
109            .finish()
110    }
111}
112
113impl<S: Clone, O> Clone for MapInto<S, O> {
114    fn clone(&self) -> Self {
115        Self::new(self.source.clone())
116    }
117}
118
119impl<S: Strategy, O: fmt::Debug> Strategy for MapInto<S, O>
120where
121    S::Value: Into<O>,
122{
123    type Tree = MapInto<S::Tree, O>;
124    type Value = O;
125
126    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
127        self.source.new_tree(runner).map(MapInto::new)
128    }
129}
130
131impl<S: ValueTree, O: fmt::Debug> ValueTree for MapInto<S, O>
132where
133    S::Value: Into<O>,
134{
135    type Value = O;
136
137    fn current(&self) -> O {
138        self.source.current().into()
139    }
140
141    fn simplify(&mut self) -> bool {
142        self.source.simplify()
143    }
144
145    fn complicate(&mut self) -> bool {
146        self.source.complicate()
147    }
148}
149
150//==============================================================================
151// Perturb
152//==============================================================================
153
154/// `Strategy` perturbation adaptor.
155///
156/// See `Strategy::prop_perturb()`.
157#[must_use = "strategies do nothing unless used"]
158pub struct Perturb<S, F> {
159    pub(super) source: S,
160    pub(super) fun: Arc<F>,
161}
162
163impl<S: fmt::Debug, F> fmt::Debug for Perturb<S, F> {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        f.debug_struct("Perturb")
166            .field("source", &self.source)
167            .field("fun", &"<function>")
168            .finish()
169    }
170}
171
172impl<S: Clone, F> Clone for Perturb<S, F> {
173    fn clone(&self) -> Self {
174        Perturb {
175            source: self.source.clone(),
176            fun: Arc::clone(&self.fun),
177        }
178    }
179}
180
181impl<S: Strategy, O: fmt::Debug, F: Fn(S::Value, TestRng) -> O> Strategy
182    for Perturb<S, F>
183{
184    type Tree = PerturbValueTree<S::Tree, F>;
185    type Value = O;
186
187    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
188        let rng = runner.new_rng();
189
190        self.source.new_tree(runner).map(|source| PerturbValueTree {
191            source,
192            rng,
193            fun: Arc::clone(&self.fun),
194        })
195    }
196}
197
198/// `ValueTree` perturbation adaptor.
199///
200/// See `Strategy::prop_perturb()`.
201pub struct PerturbValueTree<S, F> {
202    source: S,
203    fun: Arc<F>,
204    rng: TestRng,
205}
206
207impl<S: fmt::Debug, F> fmt::Debug for PerturbValueTree<S, F> {
208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209        f.debug_struct("PerturbValueTree")
210            .field("source", &self.source)
211            .field("fun", &"<function>")
212            .field("rng", &self.rng)
213            .finish()
214    }
215}
216
217impl<S: Clone, F> Clone for PerturbValueTree<S, F> {
218    fn clone(&self) -> Self {
219        PerturbValueTree {
220            source: self.source.clone(),
221            fun: Arc::clone(&self.fun),
222            rng: self.rng.clone(),
223        }
224    }
225}
226
227impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value, TestRng) -> O> ValueTree
228    for PerturbValueTree<S, F>
229{
230    type Value = O;
231
232    fn current(&self) -> O {
233        (self.fun)(self.source.current(), self.rng.clone())
234    }
235
236    fn simplify(&mut self) -> bool {
237        self.source.simplify()
238    }
239
240    fn complicate(&mut self) -> bool {
241        self.source.complicate()
242    }
243}
244
245//==============================================================================
246// Tests
247//==============================================================================
248
249#[cfg(test)]
250mod test {
251    use std::collections::HashSet;
252
253    use rand::RngCore;
254
255    use super::*;
256    use crate::strategy::just::Just;
257
258    #[test]
259    fn test_map() {
260        TestRunner::default()
261            .run(&(0..10).prop_map(|v| v * 2), |v| {
262                assert!(0 == v % 2);
263                Ok(())
264            })
265            .unwrap();
266    }
267
268    #[test]
269    fn test_map_into() {
270        TestRunner::default()
271            .run(&(0..10u8).prop_map_into::<usize>(), |v| {
272                assert!(v < 10);
273                Ok(())
274            })
275            .unwrap();
276    }
277
278    #[test]
279    fn perturb_uses_same_rng_every_time() {
280        let mut runner = TestRunner::default();
281        let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32());
282
283        for _ in 0..16 {
284            let value = input.new_tree(&mut runner).unwrap();
285            assert_eq!(value.current(), value.current());
286        }
287    }
288
289    #[test]
290    fn perturb_uses_varying_random_seeds() {
291        let mut runner = TestRunner::default();
292        let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32());
293
294        let mut seen = HashSet::new();
295        for _ in 0..64 {
296            seen.insert(input.new_tree(&mut runner).unwrap().current());
297        }
298
299        assert_eq!(64, seen.len());
300    }
301}