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 //! Modified versions of the normal strategy combinators which take specialised
11 //! traits instead of normal functions.
12 //!
13 //! This entire module is strictly a workaround until
14 //! <https://github.com/rust-lang/rfcs/pull/1522> and
15 //! <https://github.com/rust-lang/rfcs/pull/2071> are available in stable. It
16 //! allows naming types built on the combinators without resorting to dynamic
17 //! dispatch or causing `Arc` to allocate space for a function pointer.
18 //!
19 //! External code is discouraged from using this module directly. It is
20 //! deliberately not exposed in a convenient way (i.e., via the `Strategy`
21 //! trait itself), but is nonetheless exposed since external trait implementors
22 //! may face the same issues.
23 //!
24 //! **This module is subject to removal at some point after the language
25 //! features linked above become stable.**
26 
27 use crate::std_facade::fmt;
28 
29 use crate::strategy::traits::*;
30 use crate::test_runner::*;
31 
32 //==============================================================================
33 // Filter
34 //==============================================================================
35 
36 /// Essentially `Fn (&T) -> bool`.
37 pub trait FilterFn<T> {
38     /// Test whether `t` passes the filter.
apply(&self, t: &T) -> bool39     fn apply(&self, t: &T) -> bool;
40 }
41 
42 /// Static version of `strategy::Filter`.
43 #[derive(Clone)]
44 #[must_use = "strategies do nothing unless used"]
45 pub struct Filter<S, F> {
46     source: S,
47     whence: Reason,
48     fun: F,
49 }
50 
51 impl<S, F> Filter<S, F> {
52     /// Adapt strategy `source` to reject values which do not pass `filter`,
53     /// using `whence` as the reported reason/location.
new(source: S, whence: Reason, filter: F) -> Self54     pub fn new(source: S, whence: Reason, filter: F) -> Self {
55         // NOTE: We don't use universal quantification R: Into<Reason>
56         // since the module is not conveniently exposed.
57         Filter {
58             source,
59             whence,
60             fun: filter,
61         }
62     }
63 }
64 
65 impl<S: fmt::Debug, F> fmt::Debug for Filter<S, F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result66     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67         f.debug_struct("Filter")
68             .field("source", &self.source)
69             .field("whence", &self.whence)
70             .field("fun", &"<function>")
71             .finish()
72     }
73 }
74 
75 impl<S: Strategy, F: FilterFn<S::Value> + Clone> Strategy for Filter<S, F> {
76     type Tree = Filter<S::Tree, F>;
77     type Value = S::Value;
78 
new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>79     fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
80         loop {
81             let val = self.source.new_tree(runner)?;
82             if !self.fun.apply(&val.current()) {
83                 runner.reject_local(self.whence.clone())?;
84             } else {
85                 return Ok(Filter {
86                     source: val,
87                     whence: "unused".into(),
88                     fun: self.fun.clone(),
89                 });
90             }
91         }
92     }
93 }
94 
95 impl<S: ValueTree, F: FilterFn<S::Value>> Filter<S, F> {
ensure_acceptable(&mut self)96     fn ensure_acceptable(&mut self) {
97         while !self.fun.apply(&self.source.current()) {
98             if !self.source.complicate() {
99                 panic!(
100                     "Unable to complicate filtered strategy \
101                      back into acceptable value"
102                 );
103             }
104         }
105     }
106 }
107 
108 impl<S: ValueTree, F: FilterFn<S::Value>> ValueTree for Filter<S, F> {
109     type Value = S::Value;
110 
current(&self) -> S::Value111     fn current(&self) -> S::Value {
112         self.source.current()
113     }
114 
simplify(&mut self) -> bool115     fn simplify(&mut self) -> bool {
116         if self.source.simplify() {
117             self.ensure_acceptable();
118             true
119         } else {
120             false
121         }
122     }
123 
complicate(&mut self) -> bool124     fn complicate(&mut self) -> bool {
125         if self.source.complicate() {
126             self.ensure_acceptable();
127             true
128         } else {
129             false
130         }
131     }
132 }
133 
134 //==============================================================================
135 // Map
136 //==============================================================================
137 
138 /// Essentially `Fn (T) -> Output`.
139 pub trait MapFn<T> {
140     #[allow(missing_docs)]
141     type Output: fmt::Debug;
142 
143     /// Map `T` to `Output`.
apply(&self, t: T) -> Self::Output144     fn apply(&self, t: T) -> Self::Output;
145 }
146 
147 /// Static version of `strategy::Map`.
148 #[derive(Clone)]
149 #[must_use = "strategies do nothing unless used"]
150 pub struct Map<S, F> {
151     source: S,
152     fun: F,
153 }
154 
155 impl<S, F> Map<S, F> {
156     /// Adapt strategy `source` by applying `fun` to values it produces.
new(source: S, fun: F) -> Self157     pub fn new(source: S, fun: F) -> Self {
158         Map { source, fun }
159     }
160 }
161 
162 impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result163     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164         f.debug_struct("Map")
165             .field("source", &self.source)
166             .field("fun", &"<function>")
167             .finish()
168     }
169 }
170 
171 impl<S: Strategy, F: Clone + MapFn<S::Value>> Strategy for Map<S, F> {
172     type Tree = Map<S::Tree, F>;
173     type Value = F::Output;
174 
new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>175     fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
176         self.source.new_tree(runner).map(|v| Map {
177             source: v,
178             fun: self.fun.clone(),
179         })
180     }
181 }
182 
183 impl<S: ValueTree, F: MapFn<S::Value>> ValueTree for Map<S, F> {
184     type Value = F::Output;
185 
current(&self) -> F::Output186     fn current(&self) -> F::Output {
187         self.fun.apply(self.source.current())
188     }
189 
simplify(&mut self) -> bool190     fn simplify(&mut self) -> bool {
191         self.source.simplify()
192     }
193 
complicate(&mut self) -> bool194     fn complicate(&mut self) -> bool {
195         self.source.complicate()
196     }
197 }
198 
199 impl<I, O: fmt::Debug> MapFn<I> for fn(I) -> O {
200     type Output = O;
apply(&self, x: I) -> Self::Output201     fn apply(&self, x: I) -> Self::Output {
202         self(x)
203     }
204 }
205 
static_map<S: Strategy, O: fmt::Debug>( strat: S, fun: fn(S::Value) -> O, ) -> Map<S, fn(S::Value) -> O>206 pub(crate) fn static_map<S: Strategy, O: fmt::Debug>(
207     strat: S,
208     fun: fn(S::Value) -> O,
209 ) -> Map<S, fn(S::Value) -> O> {
210     Map::new(strat, fun)
211 }
212 
213 //==============================================================================
214 // Tests
215 //==============================================================================
216 
217 #[cfg(test)]
218 mod test {
219     use super::*;
220 
221     #[test]
test_static_filter()222     fn test_static_filter() {
223         #[derive(Clone, Copy, Debug)]
224         struct MyFilter;
225         impl FilterFn<i32> for MyFilter {
226             fn apply(&self, &v: &i32) -> bool {
227                 0 == v % 3
228             }
229         }
230 
231         let input = Filter::new(0..256, "%3".into(), MyFilter);
232 
233         for _ in 0..256 {
234             let mut runner = TestRunner::default();
235             let mut case = input.new_tree(&mut runner).unwrap();
236 
237             assert!(0 == case.current() % 3);
238 
239             while case.simplify() {
240                 assert!(0 == case.current() % 3);
241             }
242             assert!(0 == case.current() % 3);
243         }
244     }
245 
246     #[test]
test_static_map()247     fn test_static_map() {
248         #[derive(Clone, Copy, Debug)]
249         struct MyMap;
250         impl MapFn<i32> for MyMap {
251             type Output = i32;
252             fn apply(&self, v: i32) -> i32 {
253                 v * 2
254             }
255         }
256 
257         let input = Map::new(0..10, MyMap);
258 
259         TestRunner::default()
260             .run(&input, |v| {
261                 assert!(0 == v % 2);
262                 Ok(())
263             })
264             .unwrap();
265     }
266 }
267