1
use proptest::prelude::*;
2

            
3
// Examples found in the Uniplate paper.
4

            
5
// Stmt and Expr to demonstrate and test multitype traversals.
6
#[derive(Eq, PartialEq, Clone, Debug)]
7
pub enum Stmt {
8
    Assign(String, Expr),
9
    Sequence(Vec<Stmt>),
10
    If(Expr, Box<Stmt>, Box<Stmt>),
11
    While(Expr, Box<Stmt>),
12
}
13

            
14
#[derive(Eq, PartialEq, Clone, Debug)]
15
pub enum Expr {
16
    Add(Box<Expr>, Box<Expr>),
17
    Sub(Box<Expr>, Box<Expr>),
18
    Mul(Box<Expr>, Box<Expr>),
19
    Div(Box<Expr>, Box<Expr>),
20
    Val(i32),
21
    Var(String),
22
    Neg(Box<Expr>),
23
}
24

            
25
use self::Expr::*;
26
use self::Stmt::*;
27
pub fn proptest_exprs() -> impl Strategy<Value = Expr> {
28
    let leafs = prop_oneof![any::<i32>().prop_map(Val), any::<String>().prop_map(Var),];
29

            
30
    leafs.prop_recursive(10, 512, 2, |inner| {
31
        prop_oneof![
32
            prop::collection::vec(inner.clone(), 2..2)
33
                .prop_map(|elems| Add(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
34
            prop::collection::vec(inner.clone(), 2..2)
35
                .prop_map(|elems| Sub(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
36
            prop::collection::vec(inner.clone(), 2..2)
37
                .prop_map(|elems| Mul(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
38
            prop::collection::vec(inner.clone(), 2..2)
39
                .prop_map(|elems| Div(Box::new(elems[0].clone()), Box::new(elems[1].clone()))),
40
            inner.prop_map(|inner| Neg(Box::new(inner.clone())))
41
        ]
42
    })
43
}
44

            
45
pub fn proptest_stmts() -> impl Strategy<Value = Stmt> {
46
    let leafs = prop_oneof![(".*", proptest_exprs()).prop_map(|(a, b)| Assign(a, b)),];
47

            
48
    leafs.prop_recursive(10, 512, 50, |inner| {
49
        prop_oneof![
50
            (proptest_exprs(), prop::collection::vec(inner.clone(), 2..2)).prop_map(
51
                move |(expr, stmts)| If(
52
                    expr,
53
                    Box::new(stmts[0].clone()),
54
                    Box::new(stmts[1].clone())
55
                )
56
            ),
57
            (proptest_exprs(), inner.clone())
58
                .prop_map(move |(expr, stmt)| While(expr, Box::new(stmt))),
59
            prop::collection::vec(inner.clone(), 0..50).prop_map(Sequence)
60
        ]
61
    })
62
}