1#![cfg_attr(clippy, allow(expl_impl_clone_on_copy))]
30
31use core::fmt;
32use core::marker::PhantomData;
33
34use crate::std_facade::Arc;
35use crate::strategy::*;
36use crate::test_runner::*;
37
38pub use crate::option::{prob, Probability};
40
41struct WrapOk<T, E>(PhantomData<T>, PhantomData<E>);
42impl<T, E> Clone for WrapOk<T, E> {
43 fn clone(&self) -> Self {
44 *self
45 }
46}
47impl<T, E> Copy for WrapOk<T, E> {}
48impl<T, E> fmt::Debug for WrapOk<T, E> {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(f, "WrapOk")
51 }
52}
53impl<T: fmt::Debug, E: fmt::Debug> statics::MapFn<T> for WrapOk<T, E> {
54 type Output = Result<T, E>;
55 fn apply(&self, t: T) -> Result<T, E> {
56 Ok(t)
57 }
58}
59struct WrapErr<T, E>(PhantomData<T>, PhantomData<E>);
60impl<T, E> Clone for WrapErr<T, E> {
61 fn clone(&self) -> Self {
62 *self
63 }
64}
65impl<T, E> Copy for WrapErr<T, E> {}
66impl<T, E> fmt::Debug for WrapErr<T, E> {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 write!(f, "WrapErr")
69 }
70}
71impl<T: fmt::Debug, E: fmt::Debug> statics::MapFn<E> for WrapErr<T, E> {
72 type Output = Result<T, E>;
73 fn apply(&self, e: E) -> Result<T, E> {
74 Err(e)
75 }
76}
77
78type MapErr<T, E> =
79 statics::Map<E, WrapErr<<T as Strategy>::Value, <E as Strategy>::Value>>;
80type MapOk<T, E> =
81 statics::Map<T, WrapOk<<T as Strategy>::Value, <E as Strategy>::Value>>;
82
83opaque_strategy_wrapper! {
84 #[derive(Clone)]
89 pub struct MaybeOk[<T, E>][where T : Strategy, E : Strategy]
90 (TupleUnion<(WA<MapErr<T, E>>, WA<MapOk<T, E>>)>)
91 -> MaybeOkValueTree<T, E>;
92 pub struct MaybeOkValueTree[<T, E>][where T : Strategy, E : Strategy]
94 (TupleUnionValueTree<(
95 LazyValueTree<statics::Map<E, WrapErr<T::Value, E::Value>>>,
96 Option<LazyValueTree<statics::Map<T, WrapOk<T::Value, E::Value>>>>,
97 )>)
98 -> Result<T::Value, E::Value>;
99}
100
101opaque_strategy_wrapper! {
102 #[derive(Clone)]
107 pub struct MaybeErr[<T, E>][where T : Strategy, E : Strategy]
108 (TupleUnion<(WA<MapOk<T, E>>, WA<MapErr<T, E>>)>)
109 -> MaybeErrValueTree<T, E>;
110 pub struct MaybeErrValueTree[<T, E>][where T : Strategy, E : Strategy]
112 (TupleUnionValueTree<(
113 LazyValueTree<statics::Map<T, WrapOk<T::Value, E::Value>>>,
114 Option<LazyValueTree<statics::Map<E, WrapErr<T::Value, E::Value>>>>,
115 )>)
116 -> Result<T::Value, E::Value>;
117}
118
119impl<T: Strategy + fmt::Debug, E: Strategy + fmt::Debug> fmt::Debug
121 for MaybeOk<T, E>
122{
123 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124 write!(f, "MaybeOk({:?})", self.0)
125 }
126}
127impl<T: Strategy + fmt::Debug, E: Strategy + fmt::Debug> fmt::Debug
128 for MaybeErr<T, E>
129{
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 write!(f, "MaybeErr({:?})", self.0)
132 }
133}
134
135impl<T: Strategy, E: Strategy> Clone for MaybeOkValueTree<T, E>
136where
137 T::Tree: Clone,
138 E::Tree: Clone,
139{
140 fn clone(&self) -> Self {
141 MaybeOkValueTree(self.0.clone())
142 }
143}
144
145impl<T: Strategy, E: Strategy> fmt::Debug for MaybeOkValueTree<T, E>
146where
147 T::Tree: fmt::Debug,
148 E::Tree: fmt::Debug,
149{
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 write!(f, "MaybeOkValueTree({:?})", self.0)
152 }
153}
154
155impl<T: Strategy, E: Strategy> Clone for MaybeErrValueTree<T, E>
156where
157 T::Tree: Clone,
158 E::Tree: Clone,
159{
160 fn clone(&self) -> Self {
161 MaybeErrValueTree(self.0.clone())
162 }
163}
164
165impl<T: Strategy, E: Strategy> fmt::Debug for MaybeErrValueTree<T, E>
166where
167 T::Tree: fmt::Debug,
168 E::Tree: fmt::Debug,
169{
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 write!(f, "MaybeErrValueTree({:?})", self.0)
172 }
173}
174
175pub fn maybe_ok<T: Strategy, E: Strategy>(t: T, e: E) -> MaybeOk<T, E> {
182 maybe_ok_weighted(0.5, t, e)
183}
184
185pub fn maybe_ok_weighted<T: Strategy, E: Strategy>(
193 probability_of_ok: impl Into<Probability>,
194 t: T,
195 e: E,
196) -> MaybeOk<T, E> {
197 let prob = probability_of_ok.into().into();
198 let (ok_weight, err_weight) = float_to_weight(prob);
199
200 MaybeOk(TupleUnion::new((
201 (
202 err_weight,
203 Arc::new(statics::Map::new(e, WrapErr(PhantomData, PhantomData))),
204 ),
205 (
206 ok_weight,
207 Arc::new(statics::Map::new(t, WrapOk(PhantomData, PhantomData))),
208 ),
209 )))
210}
211
212pub fn maybe_err<T: Strategy, E: Strategy>(t: T, e: E) -> MaybeErr<T, E> {
219 maybe_err_weighted(0.5, t, e)
220}
221
222pub fn maybe_err_weighted<T: Strategy, E: Strategy>(
230 probability_of_err: impl Into<Probability>,
231 t: T,
232 e: E,
233) -> MaybeErr<T, E> {
234 let prob = probability_of_err.into().into();
235 let (err_weight, ok_weight) = float_to_weight(prob);
236
237 MaybeErr(TupleUnion::new((
238 (
239 ok_weight,
240 Arc::new(statics::Map::new(t, WrapOk(PhantomData, PhantomData))),
241 ),
242 (
243 err_weight,
244 Arc::new(statics::Map::new(e, WrapErr(PhantomData, PhantomData))),
245 ),
246 )))
247}
248
249#[cfg(test)]
250mod test {
251 use super::*;
252
253 fn count_ok_of_1000(s: impl Strategy<Value = Result<(), ()>>) -> u32 {
254 let mut runner = TestRunner::deterministic();
255 let mut count = 0;
256 for _ in 0..1000 {
257 count += s.new_tree(&mut runner).unwrap().current().is_ok() as u32;
258 }
259
260 count
261 }
262
263 #[test]
264 fn probability_defaults_to_0p5() {
265 let count = count_ok_of_1000(maybe_err(Just(()), Just(())));
266 assert!(count > 400 && count < 600);
267 let count = count_ok_of_1000(maybe_ok(Just(()), Just(())));
268 assert!(count > 400 && count < 600);
269 }
270
271 #[test]
272 fn probability_handled_correctly() {
273 let count =
274 count_ok_of_1000(maybe_err_weighted(0.1, Just(()), Just(())));
275 assert!(count > 800 && count < 950);
276
277 let count =
278 count_ok_of_1000(maybe_err_weighted(0.9, Just(()), Just(())));
279 assert!(count > 50 && count < 150);
280
281 let count =
282 count_ok_of_1000(maybe_ok_weighted(0.9, Just(()), Just(())));
283 assert!(count > 800 && count < 950);
284
285 let count =
286 count_ok_of_1000(maybe_ok_weighted(0.1, Just(()), Just(())));
287 assert!(count > 50 && count < 150);
288 }
289
290 #[test]
291 fn shrink_to_correct_case() {
292 let mut runner = TestRunner::default();
293 {
294 let input = maybe_err(Just(()), Just(()));
295 for _ in 0..64 {
296 let mut val = input.new_tree(&mut runner).unwrap();
297 if val.current().is_ok() {
298 assert!(!val.simplify());
299 assert!(val.current().is_ok());
300 } else {
301 assert!(val.simplify());
302 assert!(val.current().is_ok());
303 }
304 }
305 }
306 {
307 let input = maybe_ok(Just(()), Just(()));
308 for _ in 0..64 {
309 let mut val = input.new_tree(&mut runner).unwrap();
310 if val.current().is_err() {
311 assert!(!val.simplify());
312 assert!(val.current().is_err());
313 } else {
314 assert!(val.simplify());
315 assert!(val.current().is_err());
316 }
317 }
318 }
319 }
320
321 #[test]
322 fn test_sanity() {
323 check_strategy_sanity(maybe_ok(0i32..100i32, 0i32..100i32), None);
324 check_strategy_sanity(maybe_err(0i32..100i32, 0i32..100i32), None);
325 }
326}