blob: 449287b88aa7c7908351e0396dc7c06241a7c3c5 [file] [log] [blame]
//-
// 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());
}
}