Skip to main content

beetry_node/decorator/
invert.rs

1use beetry_core::{Node, TickStatus};
2
3/// Swaps child success and failure while preserving running.
4pub struct Invert<N> {
5    node: N,
6}
7
8impl<N> Invert<N> {
9    #[must_use]
10    pub fn new(node: N) -> Self {
11        Self { node }
12    }
13}
14
15impl<N> Node for Invert<N>
16where
17    N: Node,
18{
19    fn tick(&mut self) -> TickStatus {
20        match self.node.tick() {
21            TickStatus::Success => TickStatus::Failure,
22            TickStatus::Failure => TickStatus::Success,
23            TickStatus::Running => TickStatus::Running,
24        }
25    }
26
27    fn abort(&mut self) {
28        self.node.abort();
29    }
30
31    fn reset(&mut self) {
32        self.node.reset();
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use beetry_core::{Node, TickStatus};
39
40    use super::*;
41    use crate::mock_test::mock_returns;
42
43    #[test]
44    fn success_becomes_failure() {
45        let mut invert = Invert::new(mock_returns([TickStatus::Success]));
46        assert_eq!(invert.tick(), TickStatus::Failure);
47    }
48
49    #[test]
50    fn failure_becomes_success() {
51        let mut invert = Invert::new(mock_returns([TickStatus::Failure]));
52        assert_eq!(invert.tick(), TickStatus::Success);
53    }
54
55    #[test]
56    fn running_stays_running() {
57        let mut invert = Invert::new(mock_returns([TickStatus::Running]));
58        assert_eq!(invert.tick(), TickStatus::Running);
59    }
60
61    #[test]
62    fn abort_is_propagated() {
63        let mut node = mock_returns([]);
64        node.expect_abort().once().return_const(());
65        let mut invert = Invert::new(node);
66        invert.abort();
67    }
68
69    #[test]
70    fn reset_is_propagated() {
71        let mut node = mock_returns([]);
72        node.expect_reset().once().return_const(());
73        let mut invert = Invert::new(node);
74        invert.reset();
75    }
76}