| //- |
| // Copyright 2017 Jason Lingle |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| //! Strategies for generating `bool` values. |
| |
| use crate::strategy::*; |
| use crate::test_runner::*; |
| |
| use rand::Rng; |
| |
| /// The type of the `ANY` constant. |
| #[derive(Clone, Copy, Debug)] |
| pub struct Any(()); |
| |
| /// Generates boolean values by picking `true` or `false` uniformly. |
| /// |
| /// Shrinks `true` to `false`. |
| pub const ANY: Any = Any(()); |
| |
| impl Strategy for Any { |
| type Tree = BoolValueTree; |
| type Value = bool; |
| |
| fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { |
| Ok(BoolValueTree::new(runner.rng().gen())) |
| } |
| } |
| |
| /// Generates boolean values by picking `true` with the given `probability` |
| /// (1.0 = always true, 0.0 = always false). |
| /// |
| /// Shrinks `true` to `false`. |
| pub fn weighted(probability: f64) -> Weighted { |
| Weighted(probability) |
| } |
| |
| /// The return type from `weighted()`. |
| #[must_use = "strategies do nothing unless used"] |
| #[derive(Clone, Copy, Debug)] |
| pub struct Weighted(f64); |
| |
| impl Strategy for Weighted { |
| type Tree = BoolValueTree; |
| type Value = bool; |
| |
| fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { |
| Ok(BoolValueTree::new(runner.rng().gen_bool(self.0))) |
| } |
| } |
| |
| /// The `ValueTree` to shrink booleans to false. |
| #[derive(Clone, Copy, Debug)] |
| pub struct BoolValueTree { |
| current: bool, |
| state: ShrinkState, |
| } |
| |
| #[derive(Clone, Copy, Debug, PartialEq)] |
| enum ShrinkState { |
| Untouched, |
| Simplified, |
| Final, |
| } |
| |
| impl BoolValueTree { |
| fn new(current: bool) -> Self { |
| BoolValueTree { |
| current, |
| state: ShrinkState::Untouched, |
| } |
| } |
| } |
| |
| impl ValueTree for BoolValueTree { |
| type Value = bool; |
| |
| fn current(&self) -> bool { |
| self.current |
| } |
| fn simplify(&mut self) -> bool { |
| match self.state { |
| ShrinkState::Untouched if self.current => { |
| self.current = false; |
| self.state = ShrinkState::Simplified; |
| true |
| } |
| |
| ShrinkState::Untouched |
| | ShrinkState::Simplified |
| | ShrinkState::Final => { |
| self.state = ShrinkState::Final; |
| false |
| } |
| } |
| } |
| fn complicate(&mut self) -> bool { |
| match self.state { |
| ShrinkState::Untouched | ShrinkState::Final => { |
| self.state = ShrinkState::Final; |
| false |
| } |
| |
| ShrinkState::Simplified => { |
| self.current = true; |
| self.state = ShrinkState::Final; |
| true |
| } |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| #[test] |
| fn test_sanity() { |
| check_strategy_sanity(ANY, None); |
| } |
| |
| #[test] |
| fn shrinks_properly() { |
| let mut tree = BoolValueTree::new(true); |
| assert!(tree.simplify()); |
| assert!(!tree.current()); |
| assert!(!tree.clone().simplify()); |
| assert!(tree.complicate()); |
| assert!(!tree.clone().complicate()); |
| assert!(tree.current()); |
| assert!(!tree.simplify()); |
| assert!(tree.current()); |
| |
| tree = BoolValueTree::new(false); |
| assert!(!tree.clone().simplify()); |
| assert!(!tree.clone().complicate()); |
| assert!(!tree.current()); |
| } |
| } |