use std::sync::mpsc;
use std::time::{Duration, Instant};
use bevy::time::{DelayedCommandsExt, TimePlugin};
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use super::{IDLE, RunnerPlugin};
fn delayed_exit(delay: Duration) -> Option<Duration> {
let (sender, ran) = mpsc::channel();
let started = Instant::now();
let mut app = App::new();
app.add_plugins((TimePlugin, RunnerPlugin)).add_systems(
Startup,
move |mut commands: Commands| {
let sender = sender.clone();
commands
.delayed()
.duration(delay)
.queue(move |world: &mut World| {
sender.send(Instant::now()).ok();
world.write_message(AppExit::Success);
});
},
);
app.run();
ran.try_recv().ok().map(|at| at.duration_since(started))
}
#[test]
fn the_loop_wakes_for_a_delayed_command_within_a_frame() {
let delay = Duration::from_millis(300);
let ran = delayed_exit(delay);
assert!(
ran.is_some_and(|ran| ran >= delay && ran < delay + Duration::from_millis(200)),
"{ran:?}"
);
}
#[test]
fn a_wait_across_idle_frames_ends_on_time() {
let delay = 2 * IDLE;
let ran = delayed_exit(delay);
assert!(
ran.is_some_and(|ran| ran >= delay && ran < delay + Duration::from_millis(500)),
"{ran:?}"
);
}
#[test]
fn the_loop_wakes_at_a_wall_clock_time() {
let delay = Duration::from_millis(300);
let (sender, ran) = mpsc::channel();
let started = Instant::now();
let mut app = App::new();
app.add_plugins((TimePlugin, RunnerPlugin, crate::clock::ClockPlugin))
.add_systems(Startup, move |mut commands: Commands| {
commands.spawn(crate::clock::WakeAt::after(delay));
})
.add_observer(
move |_: On<Add<crate::clock::Due>>, mut exit: MessageWriter<AppExit>| {
sender.send(Instant::now()).ok();
exit.write(AppExit::Success);
},
);
app.run();
let ran = ran.try_recv().ok().map(|at| at.duration_since(started));
assert!(
ran.is_some_and(|ran| ran >= delay && ran < delay + Duration::from_millis(200)),
"{ran:?}"
);
}