proptest/strategy/
filter.rs1use crate::std_facade::{fmt, Arc};
11
12use crate::strategy::traits::*;
13use crate::test_runner::*;
14
15#[must_use = "strategies do nothing unless used"]
19pub struct Filter<S, F> {
20 pub(super) source: S,
21 pub(super) whence: Reason,
22 pub(super) fun: Arc<F>,
23}
24
25impl<S, F> Filter<S, F> {
26 pub(super) fn new(source: S, whence: Reason, fun: F) -> Self {
27 Self {
28 source,
29 whence,
30 fun: Arc::new(fun),
31 }
32 }
33}
34
35impl<S: fmt::Debug, F> fmt::Debug for Filter<S, F> {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 f.debug_struct("Filter")
38 .field("source", &self.source)
39 .field("whence", &self.whence)
40 .field("fun", &"<function>")
41 .finish()
42 }
43}
44
45impl<S: Clone, F> Clone for Filter<S, F> {
46 fn clone(&self) -> Self {
47 Filter {
48 source: self.source.clone(),
49 whence: "unused".into(),
50 fun: Arc::clone(&self.fun),
51 }
52 }
53}
54
55impl<S: Strategy, F: Fn(&S::Value) -> bool> Strategy for Filter<S, F> {
56 type Tree = Filter<S::Tree, F>;
57 type Value = S::Value;
58
59 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
60 loop {
61 let val = self.source.new_tree(runner)?;
62 if !(self.fun)(&val.current()) {
63 runner.reject_local(self.whence.clone())?;
64 } else {
65 return Ok(Filter {
66 source: val,
67 whence: self.whence.clone(),
68 fun: Arc::clone(&self.fun),
69 });
70 }
71 }
72 }
73}
74
75impl<S: ValueTree, F: Fn(&S::Value) -> bool> Filter<S, F> {
76 fn ensure_acceptable(&mut self) {
77 while !(self.fun)(&self.source.current()) {
78 if !self.source.complicate() {
79 panic!(
80 "Unable to complicate filtered strategy \
81 back into acceptable value"
82 );
83 }
84 }
85 }
86}
87
88impl<S: ValueTree, F: Fn(&S::Value) -> bool> ValueTree for Filter<S, F> {
89 type Value = S::Value;
90
91 fn current(&self) -> S::Value {
92 self.source.current()
93 }
94
95 fn simplify(&mut self) -> bool {
96 if self.source.simplify() {
97 self.ensure_acceptable();
98 true
99 } else {
100 false
101 }
102 }
103
104 fn complicate(&mut self) -> bool {
105 if self.source.complicate() {
106 self.ensure_acceptable();
107 true
108 } else {
109 false
110 }
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use super::*;
117
118 #[test]
119 fn test_filter() {
120 let input = (0..256).prop_filter("%3", |&v| 0 == v % 3);
121
122 for _ in 0..256 {
123 let mut runner = TestRunner::default();
124 let mut case = input.new_tree(&mut runner).unwrap();
125
126 assert!(0 == case.current() % 3);
127
128 while case.simplify() {
129 assert!(0 == case.current() % 3);
130 }
131 assert!(0 == case.current() % 3);
132 }
133 }
134
135 #[test]
136 fn test_filter_sanity() {
137 check_strategy_sanity(
138 (0..256).prop_filter("!%5", |&v| 0 != v % 5),
139 Some(CheckStrategySanityOptions {
140 strict_complicate_after_simplify: false,
143 ..CheckStrategySanityOptions::default()
144 }),
145 );
146 }
147}