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