use std::fmt;
use std::sync::Arc;
use strategy::traits::*;
use test_runner::*;
pub struct Recursive<B, F> {
pub(super) base: Arc<B>,
pub(super) recurse: Arc<F>,
pub(super) depth: u32,
pub(super) desired_size: u32,
pub(super) expected_branch_size: u32,
}
impl<B : fmt::Debug, F> fmt::Debug for Recursive<B, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Recursive")
.field("base", &self.base)
.field("recurse", &"<function>")
.field("depth", &self.depth)
.field("desired_size", &self.desired_size)
.field("expected_branch_size", &self.expected_branch_size)
.finish()
}
}
impl<B, F> Clone for Recursive<B, F> {
fn clone(&self) -> Self {
Recursive {
base: Arc::clone(&self.base),
recurse: Arc::clone(&self.recurse),
depth: self.depth,
desired_size: self.desired_size,
expected_branch_size: self.expected_branch_size,
}
}
}
impl<T : fmt::Debug + 'static,
F : Fn (Arc<BoxedStrategy<T>>) -> BoxedStrategy<T>>
Strategy for Recursive<BoxedStrategy<T>, F> {
type Value = Box<ValueTree<Value = T>>;
fn new_value(&self, runner: &mut TestRunner) -> NewTree<Self> {
let mut branch_probabilities = Vec::new();
let mut k2 = u64::from(self.expected_branch_size) * 2;
for _ in 0..self.depth {
branch_probabilities.push(f64::from(self.desired_size) / k2 as f64);
k2 = k2.saturating_mul(u64::from(self.expected_branch_size) * 2);
}
let mut strat = Arc::clone(&self.base);
while let Some(branch_probability) = branch_probabilities.pop() {
let recursive_choice = Arc::new((self.recurse)(Arc::clone(&strat)));
let non_recursive_choice = strat;
strat = Arc::new(
::bool::weighted(branch_probability.min(0.9))
.prop_ind_flat_map(move |branch| if branch {
Arc::clone(&recursive_choice)
} else {
Arc::clone(&non_recursive_choice)
}).boxed());
}
strat.new_value(runner)
}
}
#[cfg(test)]
mod test {
use std::cmp::max;
use super::*;
#[test]
fn test_recursive() {
#[derive(Clone, Debug)]
enum Tree {
Leaf,
Branch(Vec<Tree>),
}
impl Tree {
fn stats(&self) -> (u32, u32) {
match *self {
Tree::Leaf => (0, 1),
Tree::Branch(ref children) => {
let mut depth = 0;
let mut count = 0;
for child in children {
let (d, c) = child.stats();
depth = max(d, depth);
count += c;
}
(depth + 1, count + 1)
}
}
}
}
let mut max_depth = 0;
let mut max_count = 0;
let strat = Just(Tree::Leaf).prop_recursive(
4, 64, 16,
|element| ::collection::vec(element, 8..16)
.prop_map(Tree::Branch).boxed());
let mut runner = TestRunner::default();
for _ in 0..65536 {
let tree = strat.new_value(&mut runner).unwrap().current();
let (depth, count) = tree.stats();
assert!(depth <= 4, "Got depth {}", depth);
assert!(count <= 128, "Got count {}", count);
max_depth = max(depth, max_depth);
max_count = max(count, max_count);
}
assert!(max_depth >= 3, "Only got max depth {}", max_depth);
assert!(max_count > 48, "Only got max count {}", max_count);
}
}