Skip to main content

beetry_node/decorator/
until_failure.rs

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