Skip to main content

beetry_node/decorator/
fail.rs

1use beetry_core::{Node, TickStatus};
2
3/// Forces any terminal child result to become [`TickStatus::Failure`].
4pub struct Fail<N> {
5    node: N,
6}
7
8impl<N> Fail<N> {
9    #[must_use]
10    pub fn new(node: N) -> Self {
11        Self { node }
12    }
13}
14
15impl<N> Node for Fail<N>
16where
17    N: Node,
18{
19    fn tick(&mut self) -> TickStatus {
20        match self.node.tick() {
21            TickStatus::Running => TickStatus::Running,
22            TickStatus::Success | TickStatus::Failure => TickStatus::Failure,
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 success_becomes_failure() {
44        let mut fail = Fail::new(mock_returns([TickStatus::Success]));
45        assert_eq!(fail.tick(), TickStatus::Failure);
46    }
47
48    #[test]
49    fn failure_stays_failure() {
50        let mut fail = Fail::new(mock_returns([TickStatus::Failure]));
51        assert_eq!(fail.tick(), TickStatus::Failure);
52    }
53
54    #[test]
55    fn running_stays_running() {
56        let mut fail = Fail::new(mock_returns([TickStatus::Running]));
57        assert_eq!(fail.tick(), TickStatus::Running);
58    }
59
60    #[test]
61    fn abort_is_propagated() {
62        let mut node = mock_returns([]);
63        node.expect_abort().once().return_const(());
64        let mut fail = Fail::new(node);
65        fail.abort();
66    }
67
68    #[test]
69    fn reset_is_propagated() {
70        let mut node = mock_returns([]);
71        node.expect_reset().once().return_const(());
72        let mut fail = Fail::new(node);
73        fail.reset();
74    }
75}