bevy_yarnspinner 0.4.0

Bevy plugin for Yarn Spinner for Rust, friendly tool for writing game dialogue
Documentation
use bevy::ecs::event::EventCursor;
use bevy::prelude::*;
use bevy_yarnspinner::events::*;

#[derive(Debug, Default)]
pub struct EventAsserter {
    pub present_line_cursor: EventCursor<PresentLineEvent>,
    pub present_options_cursor: EventCursor<PresentOptionsEvent>,
    pub dialogue_start_cursor: EventCursor<DialogueStartEvent>,
    pub dialogue_complete_cursor: EventCursor<DialogueCompleteEvent>,
    pub node_start_cursor: EventCursor<NodeStartEvent>,
    pub node_complete_cursor: EventCursor<NodeCompleteEvent>,
    pub line_hints_cursor: EventCursor<LineHintsEvent>,
    pub execute_command_cursor: EventCursor<ExecuteCommandEvent>,
}

impl EventAsserter {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn clear_events(&mut self, app: &mut App) {
        self.present_line_cursor
            .clear(app.world().resource::<Events<PresentLineEvent>>());
        self.present_options_cursor
            .clear(app.world().resource::<Events<PresentOptionsEvent>>());
        self.dialogue_start_cursor
            .clear(app.world().resource::<Events<DialogueStartEvent>>());
        self.dialogue_complete_cursor
            .clear(app.world().resource::<Events<DialogueCompleteEvent>>());
        self.node_start_cursor
            .clear(app.world().resource::<Events<NodeStartEvent>>());
        self.node_complete_cursor
            .clear(app.world().resource::<Events<NodeCompleteEvent>>());
        self.line_hints_cursor
            .clear(app.world().resource::<Events<LineHintsEvent>>());
        self.execute_command_cursor
            .clear(app.world().resource::<Events<ExecuteCommandEvent>>());
    }
}

#[macro_export]
macro_rules! get_cursor {
    ($asserter:ident, PresentLineEvent) => {
        &mut $asserter.present_line_cursor
    };
    ($asserter:ident, PresentOptionsEvent) => {
        &mut $asserter.present_options_cursor
    };
    ($asserter:ident, DialogueStartEvent) => {
        &mut $asserter.dialogue_start_cursor
    };
    ($asserter:ident, DialogueCompleteEvent) => {
        &mut $asserter.dialogue_complete_cursor
    };
    ($asserter:ident, NodeStartEvent) => {
        &mut $asserter.node_start_cursor
    };
    ($asserter:ident, NodeCompleteEvent) => {
        &mut $asserter.node_complete_cursor
    };
    ($asserter:ident, LineHintsEvent) => {
        &mut $asserter.line_hints_cursor
    };
    ($asserter:ident, ExecuteCommandEvent) => {
        &mut $asserter.execute_command_cursor
    };
}

#[macro_export]
macro_rules! assert_events {
    ($asserter:ident, $app:ident contains [$($event:ident $((n = $num:expr))? $(with $pred:expr)?) ,* $(,)?]) => {
        $(
            { assert_events!($asserter, $app contains $event $((n = $num))? $(with $pred)?); }
        )*
    };
    ($asserter:ident, $app:ident contains $event:ident $(with $pred:expr)?) => {
        assert_events!($asserter, $app contains $event (n = 1) $(with $pred)?);
    };
    ($asserter:ident, $app:ident contains $event:ident (n = $num:expr) $(with $pred:expr)?) => {
        let events = $app.world().resource::<bevy::prelude::Events<$event>>();
        let cursor = $crate::get_cursor!($asserter, $event);
        let events: Vec<&$event> = cursor.read(&events).collect();
        assert_eq!($num, events.len(), "Expected {} events of type {}, but found {}: {events:#?}", stringify!($num), stringify!($event), events.len());
        $(
            {
                fn get_pred() -> impl Fn(&$event) -> bool {
                    $pred
                }
                let pred = get_pred();
                let actual = events.into_iter().next().unwrap();
                assert!(pred(actual), "Expected event of type {} to fulfill predicate {}, but found {:#?}", stringify!($event), stringify!($pred), actual);
            }
        )?
    };
}