//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 or the MIT license // , 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 { 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 { 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()); } }