1use crate::std_facade::{fmt, Arc};
11use core::mem;
12
13use crate::strategy::fuse::Fuse;
14use crate::strategy::traits::*;
15use crate::test_runner::*;
16
17#[derive(Debug, Clone, Copy)]
21#[must_use = "strategies do nothing unless used"]
22pub struct Flatten<S> {
23 source: S,
24}
25
26impl<S: Strategy> Flatten<S> {
27 pub fn new(source: S) -> Self {
29 Flatten { source }
30 }
31}
32
33impl<S: Strategy> Strategy for Flatten<S>
34where
35 S::Value: Strategy,
36{
37 type Tree = FlattenValueTree<S::Tree>;
38 type Value = <S::Value as Strategy>::Value;
39
40 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
41 let meta = self.source.new_tree(runner)?;
42 FlattenValueTree::new(runner, meta)
43 }
44}
45
46pub struct FlattenValueTree<S: ValueTree>
48where
49 S::Value: Strategy,
50{
51 meta: Fuse<S>,
52 current: Fuse<<S::Value as Strategy>::Tree>,
53 final_complication: Option<Fuse<<S::Value as Strategy>::Tree>>,
56 runner: TestRunner,
67 complicate_regen_remaining: u32,
68}
69
70impl<S: ValueTree> Clone for FlattenValueTree<S>
71where
72 S::Value: Strategy + Clone,
73 S: Clone,
74 <S::Value as Strategy>::Tree: Clone,
75{
76 fn clone(&self) -> Self {
77 FlattenValueTree {
78 meta: self.meta.clone(),
79 current: self.current.clone(),
80 final_complication: self.final_complication.clone(),
81 runner: self.runner.clone(),
82 complicate_regen_remaining: self.complicate_regen_remaining,
83 }
84 }
85}
86
87impl<S: ValueTree> fmt::Debug for FlattenValueTree<S>
88where
89 S::Value: Strategy,
90 S: fmt::Debug,
91 <S::Value as Strategy>::Tree: fmt::Debug,
92{
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 f.debug_struct("FlattenValueTree")
95 .field("meta", &self.meta)
96 .field("current", &self.current)
97 .field("final_complication", &self.final_complication)
98 .field(
99 "complicate_regen_remaining",
100 &self.complicate_regen_remaining,
101 )
102 .finish()
103 }
104}
105
106impl<S: ValueTree> FlattenValueTree<S>
107where
108 S::Value: Strategy,
109{
110 fn new(runner: &mut TestRunner, meta: S) -> Result<Self, Reason> {
111 let current = meta.current().new_tree(runner)?;
112 Ok(FlattenValueTree {
113 meta: Fuse::new(meta),
114 current: Fuse::new(current),
115 final_complication: None,
116 runner: runner.partial_clone(),
117 complicate_regen_remaining: 0,
118 })
119 }
120}
121
122impl<S: ValueTree> ValueTree for FlattenValueTree<S>
123where
124 S::Value: Strategy,
125{
126 type Value = <S::Value as Strategy>::Value;
127
128 fn current(&self) -> Self::Value {
129 self.current.current()
130 }
131
132 fn simplify(&mut self) -> bool {
133 self.complicate_regen_remaining = 0;
134
135 if self.current.simplify() {
136 self.meta.disallow_complicate();
142 self.final_complication = None;
143 true
144 } else if !self.meta.simplify() {
145 false
146 } else if let Ok(v) = self.meta.current().new_tree(&mut self.runner) {
147 self.current.disallow_complicate();
153 self.final_complication = Some(Fuse::new(v));
154 mem::swap(
155 self.final_complication.as_mut().unwrap(),
156 &mut self.current,
157 );
158 self.complicate_regen_remaining = self.runner.config().cases;
160 true
161 } else {
162 false
163 }
164 }
165
166 fn complicate(&mut self) -> bool {
167 if self.complicate_regen_remaining > 0 {
168 if self.runner.flat_map_regen() {
169 self.complicate_regen_remaining -= 1;
170
171 if let Ok(v) = self.meta.current().new_tree(&mut self.runner) {
172 self.current = Fuse::new(v);
173 return true;
174 }
175 } else {
176 self.complicate_regen_remaining = 0;
177 }
178 }
179
180 if self.current.complicate() {
181 return true;
182 } else if self.meta.complicate() {
183 if let Ok(v) = self.meta.current().new_tree(&mut self.runner) {
184 self.complicate_regen_remaining = self.runner.config().cases;
185 self.current = Fuse::new(v);
186 return true;
187 }
188 }
189
190 if let Some(v) = self.final_complication.take() {
191 self.current = v;
192 true
193 } else {
194 false
195 }
196 }
197}
198
199#[derive(Clone, Copy, Debug)]
203pub struct IndFlatten<S>(pub(super) S);
204
205impl<S: Strategy> Strategy for IndFlatten<S>
206where
207 S::Value: Strategy,
208{
209 type Tree = <S::Value as Strategy>::Tree;
210 type Value = <S::Value as Strategy>::Value;
211
212 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
213 let inner = self.0.new_tree(runner)?;
214 inner.current().new_tree(runner)
215 }
216}
217
218pub struct IndFlattenMap<S, F> {
223 pub(super) source: S,
224 pub(super) fun: Arc<F>,
225}
226
227impl<S: fmt::Debug, F> fmt::Debug for IndFlattenMap<S, F> {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 f.debug_struct("IndFlattenMap")
230 .field("source", &self.source)
231 .field("fun", &"<function>")
232 .finish()
233 }
234}
235
236impl<S: Clone, F> Clone for IndFlattenMap<S, F> {
237 fn clone(&self) -> Self {
238 IndFlattenMap {
239 source: self.source.clone(),
240 fun: Arc::clone(&self.fun),
241 }
242 }
243}
244
245impl<S: Strategy, R: Strategy, F: Fn(S::Value) -> R> Strategy
246 for IndFlattenMap<S, F>
247{
248 type Tree = crate::tuple::TupleValueTree<(S::Tree, R::Tree)>;
249 type Value = (S::Value, R::Value);
250
251 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
252 let left = self.source.new_tree(runner)?;
253 let right_source = (self.fun)(left.current());
254 let right = right_source.new_tree(runner)?;
255
256 Ok(crate::tuple::TupleValueTree::new((left, right)))
257 }
258}
259
260#[cfg(test)]
261mod test {
262 use super::*;
263
264 use std::u32;
265
266 use crate::strategy::just::Just;
267 use crate::test_runner::Config;
268
269 #[test]
270 fn test_flat_map() {
271 let input = (0..65536).prop_flat_map(|a| (Just(a), (a - 5..a + 5)));
275
276 let mut failures = 0;
277 let mut runner = TestRunner::new_with_rng(
278 Config {
279 max_shrink_iters: u32::MAX - 1,
280 ..Config::default()
281 },
282 TestRng::deterministic_rng(RngAlgorithm::default()),
283 );
284 for _ in 0..1000 {
285 let case = input.new_tree(&mut runner).unwrap();
286 let result = runner.run_one(case, |(a, b)| {
287 if a <= 10000 || b <= a {
288 Ok(())
289 } else {
290 Err(TestCaseError::fail("fail"))
291 }
292 });
293
294 match result {
295 Ok(_) => {}
296 Err(TestError::Fail(_, v)) => {
297 failures += 1;
298 assert_eq!((10001, 10002), v);
299 }
300 result => panic!("Unexpected result: {:?}", result),
301 }
302 }
303
304 assert!(failures > 250);
305 }
306
307 #[test]
308 fn test_flat_map_sanity() {
309 check_strategy_sanity(
310 (0..65536).prop_flat_map(|a| (Just(a), (a - 5..a + 5))),
311 None,
312 );
313 }
314
315 #[test]
316 fn flat_map_respects_regen_limit() {
317 use std::sync::atomic::{AtomicBool, Ordering};
318
319 let input = (0..65536)
320 .prop_flat_map(|_| 0..65536)
321 .prop_flat_map(|_| 0..65536)
322 .prop_flat_map(|_| 0..65536)
323 .prop_flat_map(|_| 0..65536)
324 .prop_flat_map(|_| 0..65536);
325
326 let pass = AtomicBool::new(false);
332 let mut runner = TestRunner::new(Config {
333 max_flat_map_regens: 1000,
334 ..Config::default()
335 });
336 let case = input.new_tree(&mut runner).unwrap();
337 let _ = runner.run_one(case, |_| {
338 prop_assert!(pass.fetch_or(true, Ordering::SeqCst));
340 Ok(())
341 });
342 }
343
344 #[test]
345 fn test_ind_flat_map_sanity() {
346 check_strategy_sanity(
347 (0..65536).prop_ind_flat_map(|a| (Just(a), (a - 5..a + 5))),
348 None,
349 );
350 }
351
352 #[test]
353 fn test_ind_flat_map2_sanity() {
354 check_strategy_sanity(
355 (0..65536).prop_ind_flat_map2(|a| a - 5..a + 5),
356 None,
357 );
358 }
359}