1
use tree_morph::prelude::*;
2
use uniplate::Uniplate;
3

            
4
#[derive(Debug, PartialEq, Eq, Clone, Uniplate)]
5
enum Expr {
6
    Lit(i32),
7
    Add(Box<Expr>, Box<Expr>),
8
    Neg(Box<Expr>),
9
}
10

            
11
#[derive(Default)]
12
struct Meta {
13
    before_downs: i32,
14
    after_downs: i32,
15
    before_rights: i32,
16
    after_rights: i32,
17
    before_ups: i32,
18
    after_ups: i32,
19
    stack: Vec<Expr>,
20
}
21

            
22
impl Meta {
23
    fn new() -> Self {
24
        Default::default()
25
    }
26
}
27

            
28
fn do_nothing(_: &mut Commands<Expr, Meta>, _: &Expr, _: &Meta) -> Option<Expr> {
29
    None
30
}
31

            
32
#[test]
33
fn explore_once_events_called_correct_amount() {
34
    let expr = Expr::Add(Box::new(Expr::Lit(1)), Box::new(Expr::Lit(1)));
35

            
36
    let engine = EngineBuilder::new()
37
        .add_rule(do_nothing)
38
        .add_before_up(|_, meta| meta.before_ups += 1)
39
        .add_after_up(|_, meta| meta.after_ups += 1)
40
        .add_before_down(|node, meta| {
41
            meta.before_downs += 1;
42
            println!("{node:?}")
43
        })
44
        .add_after_down(|_, meta| meta.after_downs += 1)
45
        .add_before_right(|_, meta| meta.before_rights += 1)
46
        .add_after_right(|_, meta| meta.after_rights += 1)
47
        .build();
48
    let (_, new_meta) = engine.morph(expr, Meta::new());
49

            
50
    // Moves down, right, up
51
    assert_eq!(new_meta.before_ups, 1);
52
    assert_eq!(new_meta.after_ups, 1);
53
    assert_eq!(new_meta.before_downs, 1);
54
    assert_eq!(new_meta.after_downs, 1);
55
    assert_eq!(new_meta.before_rights, 1);
56
    assert_eq!(new_meta.after_rights, 1);
57
}
58

            
59
#[test]
60
fn explore_nested_events_called_correct_amount() {
61
    let expr = Expr::Neg(Box::new(Expr::Neg(Box::new(Expr::Neg(Box::new(
62
        Expr::Lit(1),
63
    ))))));
64

            
65
    let engine = EngineBuilder::new()
66
        .add_rule(do_nothing)
67
        .add_before_up(|_, meta| meta.before_ups += 1)
68
        .add_after_up(|_, meta| meta.after_ups += 1)
69
        .add_before_down(|_, meta| meta.before_downs += 1)
70
        .add_after_down(|_, meta| meta.after_downs += 1)
71
        .add_before_right(|_, meta| meta.before_rights += 1)
72
        .add_after_right(|_, meta| meta.after_rights += 1)
73
        .build();
74
    let (_, new_meta) = engine.morph(expr, Meta::new());
75

            
76
    // Moves down, down, down, up, up, up
77
    assert_eq!(new_meta.before_ups, 3);
78
    assert_eq!(new_meta.after_ups, 3);
79
    assert_eq!(new_meta.before_downs, 3);
80
    assert_eq!(new_meta.after_downs, 3);
81
    assert_eq!(new_meta.before_rights, 0);
82
    assert_eq!(new_meta.after_rights, 0);
83
}
84

            
85
#[test]
86
fn correct_order_pushed_to_stack() {
87
    let expr = Expr::Add(
88
        Box::new(Expr::Neg(Box::new(Expr::Lit(42)))),
89
        Box::new(Expr::Lit(0)),
90
    );
91

            
92
    let engine = EngineBuilder::new()
93
        .add_rule(|_: &mut Commands<_, _>, expr: &Expr, meta: &Meta| {
94
            if let Expr::Lit(42) = expr {
95
                // We are at the first leaf, the path from the root should be in the stack
96
                assert!(matches!(meta.stack[0], Expr::Add(_, _)));
97
                assert!(matches!(meta.stack[1], Expr::Neg(_)));
98
            }
99
            None
100
        })
101
        .add_before_down(|subtree, meta| meta.stack.push(subtree.clone()))
102
        .add_after_up(|_, meta| {
103
            meta.stack.pop().expect("empty stack popped");
104
        })
105
        .build();
106
    let (_, new_meta) = engine.morph(expr, Meta::new());
107

            
108
    // After returning to the root, the stack should be empty.
109
    assert_eq!(new_meta.stack.len(), 0);
110
}