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 
10 use crate::std_facade::Arc;
11 use core::fmt;
12 use core::marker::PhantomData;
13 
14 use crate::strategy::traits::*;
15 use 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"]
25 pub struct Map<S, F> {
26     pub(super) source: S,
27     pub(super) fun: Arc<F>,
28 }
29 
30 impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result31     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 
39 impl<S: Clone, F> Clone for Map<S, F> {
clone(&self) -> Self40     fn clone(&self) -> Self {
41         Map {
42             source: self.source.clone(),
43             fun: Arc::clone(&self.fun),
44         }
45     }
46 }
47 
48 impl<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 
new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>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 
60 impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value) -> O> ValueTree
61     for Map<S, F>
62 {
63     type Value = O;
64 
current(&self) -> O65     fn current(&self) -> O {
66         (self.fun)(self.source.current())
67     }
68 
simplify(&mut self) -> bool69     fn simplify(&mut self) -> bool {
70         self.source.simplify()
71     }
72 
complicate(&mut self) -> bool73     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"]
89 pub struct MapInto<S, O> {
90     pub(super) source: S,
91     pub(super) output: PhantomData<O>,
92 }
93 
94 impl<S, O> MapInto<S, O> {
95     /// Construct a `MapInto` mapper from an `S` strategy into a strategy
96     /// producing `O`s.
new(source: S) -> Self97     pub(super) fn new(source: S) -> Self {
98         Self {
99             source,
100             output: PhantomData,
101         }
102     }
103 }
104 
105 impl<S: fmt::Debug, O> fmt::Debug for MapInto<S, O> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result106     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107         f.debug_struct("MapInto")
108             .field("source", &self.source)
109             .finish()
110     }
111 }
112 
113 impl<S: Clone, O> Clone for MapInto<S, O> {
clone(&self) -> Self114     fn clone(&self) -> Self {
115         Self::new(self.source.clone())
116     }
117 }
118 
119 impl<S: Strategy, O: fmt::Debug> Strategy for MapInto<S, O>
120 where
121     S::Value: Into<O>,
122 {
123     type Tree = MapInto<S::Tree, O>;
124     type Value = O;
125 
new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>126     fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
127         self.source.new_tree(runner).map(MapInto::new)
128     }
129 }
130 
131 impl<S: ValueTree, O: fmt::Debug> ValueTree for MapInto<S, O>
132 where
133     S::Value: Into<O>,
134 {
135     type Value = O;
136 
current(&self) -> O137     fn current(&self) -> O {
138         self.source.current().into()
139     }
140 
simplify(&mut self) -> bool141     fn simplify(&mut self) -> bool {
142         self.source.simplify()
143     }
144 
complicate(&mut self) -> bool145     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"]
158 pub struct Perturb<S, F> {
159     pub(super) source: S,
160     pub(super) fun: Arc<F>,
161 }
162 
163 impl<S: fmt::Debug, F> fmt::Debug for Perturb<S, F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result164     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 
172 impl<S: Clone, F> Clone for Perturb<S, F> {
clone(&self) -> Self173     fn clone(&self) -> Self {
174         Perturb {
175             source: self.source.clone(),
176             fun: Arc::clone(&self.fun),
177         }
178     }
179 }
180 
181 impl<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 
new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>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()`.
201 pub struct PerturbValueTree<S, F> {
202     source: S,
203     fun: Arc<F>,
204     rng: TestRng,
205 }
206 
207 impl<S: fmt::Debug, F> fmt::Debug for PerturbValueTree<S, F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result208     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 
217 impl<S: Clone, F> Clone for PerturbValueTree<S, F> {
clone(&self) -> Self218     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 
227 impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value, TestRng) -> O> ValueTree
228     for PerturbValueTree<S, F>
229 {
230     type Value = O;
231 
current(&self) -> O232     fn current(&self) -> O {
233         (self.fun)(self.source.current(), self.rng.clone())
234     }
235 
simplify(&mut self) -> bool236     fn simplify(&mut self) -> bool {
237         self.source.simplify()
238     }
239 
complicate(&mut self) -> bool240     fn complicate(&mut self) -> bool {
241         self.source.complicate()
242     }
243 }
244 
245 //==============================================================================
246 // Tests
247 //==============================================================================
248 
249 #[cfg(test)]
250 mod test {
251     use std::collections::HashSet;
252 
253     use rand::RngCore;
254 
255     use super::*;
256     use crate::strategy::just::Just;
257 
258     #[test]
test_map()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]
test_map_into()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]
perturb_uses_same_rng_every_time()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]
perturb_uses_varying_random_seeds()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 }
302