Skip to main content

rmv_bevy_testing_tools/traits/
manage_state.rs

1use bevy_state::state::{FreelyMutableState, NextState, State, States};
2
3use crate::prelude::TestApp;
4
5#[doc = include_str!("./manage_state.md")]
6pub trait ManageState {
7    fn get_state<S: States>(&self) -> Option<&S>;
8    fn get_next_state<S: FreelyMutableState>(&self) -> Option<&NextState<S>>;
9    fn set_next_state<S: FreelyMutableState>(&mut self, next: S) -> Option<()>;
10}
11
12impl ManageState for TestApp {
13    fn get_state<S: States>(&self) -> Option<&S> {
14        self.world().get_resource::<State<S>>().map(|s| s.get())
15    }
16    fn get_next_state<S: FreelyMutableState>(&self) -> Option<&NextState<S>> {
17        self.world().get_resource::<NextState<S>>()
18    }
19    fn set_next_state<S: FreelyMutableState>(&mut self, next: S) -> Option<()> {
20        self.world_mut()
21            .get_resource_mut::<NextState<S>>()
22            .map(|mut s| s.set(next))
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use std::env;
29
30    use bevy_state::{
31        app::{AppExtStates, StatesPlugin},
32        state::{NextState, States},
33    };
34    use rstest::{fixture, rstest};
35    use speculoos::{assert_that, asserting, option::OptionAssertions, string::StrAssertions};
36
37    use crate::{
38        prelude::{minimal_test_app, TestApp},
39        traits::ManageState,
40    };
41
42    #[rstest]
43    fn trait_manage_state(#[from(minimal_test_app)] mut app: TestApp) {
44        // we don't want to run this test, but it has to compile.
45        // this is just so the compiler doesn't remove this code
46        if env::var("_IF_IT_COMPILES_ITS_FINE_")
47            .map(|s| s == "true")
48            .unwrap_or(true)
49        {
50            return;
51        }
52
53        #[derive(States, Debug, Default, Hash, PartialEq, Eq, Clone, Copy)]
54        enum MyState {
55            #[default]
56            A,
57            B,
58        }
59
60        app.init_state::<MyState>();
61        app.set_next_state(MyState::B);
62    }
63
64    #[derive(States, Debug, Copy, Clone, PartialEq, Eq, Hash)]
65    enum MyState {
66        First,
67        Second,
68    }
69
70    #[fixture]
71    fn states_app(
72        #[from(minimal_test_app)]
73        #[with(StatesPlugin)]
74        app: TestApp,
75    ) -> TestApp {
76        app
77    }
78
79    #[rstest]
80    fn test_app_get_state(#[from(states_app)] mut app: TestApp) {
81        asserting!("TestApp::get_state() before MyState exists")
82            .that(&app.get_state::<MyState>())
83            .is_none();
84
85        app.insert_state(MyState::First);
86
87        asserting!("TestApp::get_state() when MyState exists")
88            .that(&app.get_state::<MyState>())
89            .is_some()
90            .is_equal_to(&MyState::First);
91    }
92
93    #[rstest]
94    fn test_app_get_next_state(#[from(states_app)] mut app: TestApp) {
95        asserting!("TestApp::get_next_state() before MyState exists")
96            .that(&app.get_next_state::<MyState>())
97            .is_none();
98
99        app.insert_state(MyState::First);
100
101        let next_state = app.get_next_state::<MyState>();
102
103        asserting!("TestApp::get_next_state() when MyState exists")
104            .that(&next_state)
105            .is_some();
106        assert_that!(format!("{:?}", next_state.unwrap()))
107            .is_equal_to(format!("{:?}", NextState::<MyState>::Unchanged));
108    }
109
110    #[rstest]
111    fn test_app_set_next_state(#[from(states_app)] mut app: TestApp) {
112        asserting!("TestApp::set_next_state() before MyState exists")
113            .that(&app.set_next_state(MyState::First))
114            .is_none();
115
116        app.insert_state(MyState::First);
117        asserting!("TestApp::set_next_state() before MyState exists")
118            .that(&app.set_next_state(MyState::Second))
119            .is_some();
120
121        let next_state = app.get_next_state::<MyState>();
122        asserting!("TestApp::get_next_state() after set_next_state()")
123            .that(&next_state)
124            .is_some();
125        assert_that!(format!("{:?}", next_state.unwrap()))
126            .contains(format!("{:?}", MyState::Second));
127    }
128}