1use crate::Handler;
13use crate::world::{Registry, World, WorldBuilder};
14
15pub struct TestHarness {
49 world: World,
50}
51
52impl TestHarness {
53 pub fn new(builder: WorldBuilder) -> Self {
55 Self {
56 world: builder.build(),
57 }
58 }
59
60 pub fn registry(&self) -> &Registry {
62 self.world.registry()
63 }
64
65 pub fn dispatch<E>(&mut self, handler: &mut impl Handler<E>, event: E) {
67 self.world.next_sequence();
68 handler.run(&mut self.world, event);
69 }
70
71 pub fn dispatch_many<E>(
73 &mut self,
74 handler: &mut impl Handler<E>,
75 events: impl IntoIterator<Item = E>,
76 ) {
77 for event in events {
78 self.dispatch(handler, event);
79 }
80 }
81
82 pub fn world(&self) -> &World {
84 &self.world
85 }
86
87 pub fn world_mut(&mut self) -> &mut World {
89 &mut self.world
90 }
91}
92
93#[cfg(feature = "timer")]
98mod timer_driver {
99 use std::ops::DerefMut;
100 use std::time::{Duration, Instant};
101
102 use crate::Handler;
103 use crate::timer::TimerPoller;
104 use crate::world::World;
105
106 pub struct TestTimerDriver<S: 'static = Box<dyn Handler<Instant>>> {
144 poller: TimerPoller<S>,
145 now: Instant,
146 }
147
148 impl<S: DerefMut + Send + 'static> TestTimerDriver<S>
149 where
150 S::Target: Handler<Instant>,
151 {
152 pub fn new(poller: TimerPoller<S>) -> Self {
155 Self {
156 poller,
157 now: Instant::now(),
158 }
159 }
160
161 pub fn now(&self) -> Instant {
163 self.now
164 }
165
166 pub fn advance(&mut self, duration: Duration) {
168 self.now += duration;
169 }
170
171 pub fn set_now(&mut self, now: Instant) {
173 self.now = now;
174 }
175
176 pub fn poll(&mut self, world: &mut World) -> usize {
181 self.poller.poll(world, self.now)
182 }
183
184 pub fn next_deadline(&self, world: &World) -> Option<Instant> {
186 self.poller.next_deadline(world)
187 }
188
189 pub fn len(&self, world: &World) -> usize {
191 self.poller.len(world)
192 }
193
194 pub fn is_empty(&self, world: &World) -> bool {
196 self.poller.is_empty(world)
197 }
198 }
199}
200
201#[cfg(feature = "timer")]
202pub use timer_driver::TestTimerDriver;
203
204#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::{IntoHandler, ResMut};
212
213 fn accumulate(mut counter: ResMut<u64>, event: u64) {
216 *counter += event;
217 }
218
219 #[test]
220 fn dispatch_advances_sequence() {
221 let mut builder = WorldBuilder::new();
222 builder.register::<u64>(0);
223 let mut harness = TestHarness::new(builder);
224
225 let seq_before = harness.world().current_sequence();
226 let mut handler = accumulate.into_handler(harness.registry());
227 harness.dispatch(&mut handler, 1u64);
228 assert_eq!(harness.world().current_sequence().0, seq_before.0 + 1);
229 }
230
231 #[test]
232 fn dispatch_runs_handler() {
233 let mut builder = WorldBuilder::new();
234 builder.register::<u64>(0);
235 let mut harness = TestHarness::new(builder);
236
237 let mut handler = accumulate.into_handler(harness.registry());
238 harness.dispatch(&mut handler, 10u64);
239 assert_eq!(*harness.world().resource::<u64>(), 10);
240 }
241
242 #[test]
243 fn dispatch_many_sequential() {
244 let mut builder = WorldBuilder::new();
245 builder.register::<u64>(0);
246 let mut harness = TestHarness::new(builder);
247
248 let seq_before = harness.world().current_sequence();
249 let mut handler = accumulate.into_handler(harness.registry());
250 harness.dispatch_many(&mut handler, [10u64, 5, 3]);
251 assert_eq!(*harness.world().resource::<u64>(), 18);
252 assert_eq!(harness.world().current_sequence().0, seq_before.0 + 3);
253 }
254
255 #[test]
256 fn world_access() {
257 let mut builder = WorldBuilder::new();
258 builder.register::<u64>(42);
259 let mut harness = TestHarness::new(builder);
260
261 assert_eq!(*harness.world().resource::<u64>(), 42);
262
263 *harness.world_mut().resource_mut::<u64>() = 99;
264 assert_eq!(*harness.world().resource::<u64>(), 99);
265 }
266
267 #[cfg(feature = "timer")]
270 mod timer_tests {
271 use crate::testing::TestTimerDriver;
272 use crate::timer::{TimerInstaller, TimerPoller, TimerWheel, Wheel};
273 use crate::{IntoHandler, ResMut, WorldBuilder};
274 use std::time::{Duration, Instant};
275
276 fn set_flag(mut flag: ResMut<bool>, _now: Instant) {
277 *flag = true;
278 }
279
280 #[test]
281 fn advance_moves_time() {
282 let mut builder = WorldBuilder::new();
283 let poller: TimerPoller =
284 builder.install_driver(TimerInstaller::new(Wheel::unbounded(64, Instant::now())));
285 let mut timer = TestTimerDriver::new(poller);
286
287 let start = timer.now();
288 timer.advance(Duration::from_millis(100));
289 assert_eq!(timer.now(), start + Duration::from_millis(100));
290 }
291
292 #[test]
293 fn poll_fires_expired() {
294 let mut builder = WorldBuilder::new();
295 builder.register::<bool>(false);
296 let poller: TimerPoller =
297 builder.install_driver(TimerInstaller::new(Wheel::unbounded(64, Instant::now())));
298 let mut timer = TestTimerDriver::new(poller);
299 let mut world = builder.build();
300
301 let deadline = timer.now() + Duration::from_millis(100);
302 let handler = set_flag.into_handler(world.registry());
303 world
304 .resource_mut::<TimerWheel>()
305 .schedule_forget(deadline, Box::new(handler));
306
307 timer.advance(Duration::from_millis(150));
308 let fired = timer.poll(&mut world);
309 assert_eq!(fired, 1);
310 assert!(*world.resource::<bool>());
311 }
312
313 #[test]
314 fn poll_skips_future() {
315 let mut builder = WorldBuilder::new();
316 builder.register::<bool>(false);
317 let poller: TimerPoller =
318 builder.install_driver(TimerInstaller::new(Wheel::unbounded(64, Instant::now())));
319 let mut timer = TestTimerDriver::new(poller);
320 let mut world = builder.build();
321
322 let deadline = timer.now() + Duration::from_secs(60);
323 let handler = set_flag.into_handler(world.registry());
324 world
325 .resource_mut::<TimerWheel>()
326 .schedule_forget(deadline, Box::new(handler));
327
328 let fired = timer.poll(&mut world);
329 assert_eq!(fired, 0);
330 assert!(!*world.resource::<bool>());
331 }
332
333 #[test]
334 fn set_now_overrides() {
335 let mut builder = WorldBuilder::new();
336 let poller: TimerPoller =
337 builder.install_driver(TimerInstaller::new(Wheel::unbounded(64, Instant::now())));
338 let mut timer = TestTimerDriver::new(poller);
339
340 let target = timer.now() + Duration::from_secs(999);
341 timer.set_now(target);
342 assert_eq!(timer.now(), target);
343 }
344 }
345}