proptest/
bool.rs

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//! Strategies for generating `bool` values.
11
12use crate::strategy::*;
13use crate::test_runner::*;
14
15use rand::Rng;
16
17/// The type of the `ANY` constant.
18#[derive(Clone, Copy, Debug)]
19pub struct Any(());
20
21/// Generates boolean values by picking `true` or `false` uniformly.
22///
23/// Shrinks `true` to `false`.
24pub const ANY: Any = Any(());
25
26impl Strategy for Any {
27    type Tree = BoolValueTree;
28    type Value = bool;
29
30    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
31        Ok(BoolValueTree::new(runner.rng().gen()))
32    }
33}
34
35/// Generates boolean values by picking `true` with the given `probability`
36/// (1.0 = always true, 0.0 = always false).
37///
38/// Shrinks `true` to `false`.
39pub fn weighted(probability: f64) -> Weighted {
40    Weighted(probability)
41}
42
43/// The return type from `weighted()`.
44#[must_use = "strategies do nothing unless used"]
45#[derive(Clone, Copy, Debug)]
46pub struct Weighted(f64);
47
48impl Strategy for Weighted {
49    type Tree = BoolValueTree;
50    type Value = bool;
51
52    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
53        Ok(BoolValueTree::new(runner.rng().gen_bool(self.0)))
54    }
55}
56
57/// The `ValueTree` to shrink booleans to false.
58#[derive(Clone, Copy, Debug)]
59pub struct BoolValueTree {
60    current: bool,
61    state: ShrinkState,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq)]
65enum ShrinkState {
66    Untouched,
67    Simplified,
68    Final,
69}
70
71impl BoolValueTree {
72    fn new(current: bool) -> Self {
73        BoolValueTree {
74            current,
75            state: ShrinkState::Untouched,
76        }
77    }
78}
79
80impl ValueTree for BoolValueTree {
81    type Value = bool;
82
83    fn current(&self) -> bool {
84        self.current
85    }
86    fn simplify(&mut self) -> bool {
87        match self.state {
88            ShrinkState::Untouched if self.current => {
89                self.current = false;
90                self.state = ShrinkState::Simplified;
91                true
92            }
93
94            ShrinkState::Untouched
95            | ShrinkState::Simplified
96            | ShrinkState::Final => {
97                self.state = ShrinkState::Final;
98                false
99            }
100        }
101    }
102    fn complicate(&mut self) -> bool {
103        match self.state {
104            ShrinkState::Untouched | ShrinkState::Final => {
105                self.state = ShrinkState::Final;
106                false
107            }
108
109            ShrinkState::Simplified => {
110                self.current = true;
111                self.state = ShrinkState::Final;
112                true
113            }
114        }
115    }
116}
117
118#[cfg(test)]
119mod test {
120    use super::*;
121
122    #[test]
123    fn test_sanity() {
124        check_strategy_sanity(ANY, None);
125    }
126
127    #[test]
128    fn shrinks_properly() {
129        let mut tree = BoolValueTree::new(true);
130        assert!(tree.simplify());
131        assert!(!tree.current());
132        assert!(!tree.clone().simplify());
133        assert!(tree.complicate());
134        assert!(!tree.clone().complicate());
135        assert!(tree.current());
136        assert!(!tree.simplify());
137        assert!(tree.current());
138
139        tree = BoolValueTree::new(false);
140        assert!(!tree.clone().simplify());
141        assert!(!tree.clone().complicate());
142        assert!(!tree.current());
143    }
144}