Skip to main content

race_test/
handler_helpers.rs

1use std::mem::swap;
2
3use race_api::engine::GameHandler;
4use race_api::error::Result;
5use race_api::event::Event;
6use race_api::effect::Effect;
7use race_core::context::GameContext;
8use race_core::engine::{general_handle_event, general_init_state};
9use race_core::types::GameAccount;
10use race_encryptor::Encryptor;
11
12use crate::client_helpers::TestClient;
13
14fn parse_effect_checkpoint<H: GameHandler>(effect: &mut Effect) -> Result<()> {
15    if effect.is_checkpoint {
16        effect.__set_checkpoint_raw(vec![]);
17    }
18    Ok(())
19}
20
21/// A wrapped handler for testing
22/// This handler includes the general event handling, which is necessary for integration test.
23pub struct TestHandler<H>
24where
25    H: GameHandler,
26{
27    handler: H,
28}
29
30impl<H: GameHandler> TestHandler<H> {
31    pub fn init_state(context: &mut GameContext, game_account: &GameAccount) -> Result<Self> {
32        let mut new_context = context.clone();
33        let init_account = game_account.derive_init_account();
34        general_init_state(&mut new_context, &init_account)?;
35        let mut effect = new_context.derive_effect();
36        let handler = H::init_state(&mut effect, init_account)?;
37        context.apply_effect(effect)?;
38        swap(context, &mut new_context);
39        Ok(Self { handler })
40    }
41
42    pub fn handle_event(&mut self, context: &mut GameContext, event: &Event) -> Result<()> {
43        let mut new_context = context.clone();
44        let encryptor = Encryptor::default();
45        general_handle_event(&mut new_context, event, &encryptor)?;
46        let mut effect = new_context.derive_effect();
47        self.handler.handle_event(&mut effect, event.to_owned())?;
48        parse_effect_checkpoint::<H>(&mut effect)?;
49        new_context.apply_effect(effect)?;
50        swap(context, &mut new_context);
51        Ok(())
52    }
53
54    /// Find the event which is going to be disptached in the context, then process it.
55    /// In real cases, the disptached event will be handled by an event loop.
56    /// We use this function to simulate such cases, since we don't have an event loop in tests.
57    pub fn handle_dispatch_event(&mut self, context: &mut GameContext) -> Result<()> {
58        let event = context
59            .get_dispatch()
60            .as_ref()
61            .expect("No dispatch event")
62            .event
63            .clone();
64        self.handle_event(context, &event)?;
65        Ok(())
66    }
67
68    /// This fn keeps handling events of the following two types, until there is none:
69    /// 1. Event dispatched from within the (updated) context: context.dispatch
70    /// 2. Event dispatched by clients after they see the updated context
71    pub fn handle_until_no_events(
72        &mut self,
73        context: &mut GameContext,
74        event: &Event,
75        mut clients: Vec<&mut TestClient>,
76    ) -> Result<()> {
77        // 1. Process the `event'(arg) --> context updated
78        // 2. context may dispatch --> take care those with timeout == current timestamp
79        // 3. iter clients to syn with updated context --> a couple of events
80        // 4. handle these client/trans events
81        let mut evts: Vec<Event> = vec![event.clone()]; // keep handling events in this vec
82
83        while !evts.is_empty() {
84            let evt = &evts[0];
85            println!("* Received event: {}", evt);
86
87            self.handle_event(context, evt)?;
88            if evts.len() == 1 {
89                evts.clear();
90            } else {
91                evts = evts.iter().skip(1).map(|e| e.clone()).collect();
92            }
93            if let Some(ctx_evt) = context.get_dispatch() {
94                if ctx_evt.timeout == context.get_timestamp() {
95                    evts.push(ctx_evt.event.clone());
96                    context.cancel_dispatch();
97                }
98            }
99            // Handle events (responses) from Clients/transactor(s) after they see updated ctx
100            for i in 0..clients.len() {
101                let c = clients.get_mut(i).unwrap();
102                let cli_evts = c.handle_updated_context(context)?;
103                evts.extend_from_slice(&cli_evts);
104            }
105
106            if let Some(dispatch) = context.get_dispatch() {
107                println!("* Context dispatch: {:?}", dispatch);
108            }
109        }
110        Ok(())
111    }
112
113    pub fn get_state(&self) -> &H {
114        &self.handler
115    }
116
117    pub fn get_mut_state(&mut self) -> &mut H {
118        &mut self.handler
119    }
120}