1use alloc::collections::BinaryHeap;
8use alloc::format;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::fmt::{self, Debug, Formatter};
12use core::hash::Hash;
13use core::ops;
14use core::sync::atomic::Ordering;
15use core::time::Duration;
16use netstack3_sync::Mutex;
17
18use assert_matches::assert_matches;
19use netstack3_hashmap::HashMap;
20
21use crate::context::CtxPair;
22use crate::ref_counted_hash_map::{RefCountedHashSet, RemoveResult};
23use crate::time::{
24 AtomicInstant, Instant, InstantBindingsTypes, InstantContext, TimerBindingsTypes, TimerContext,
25 TimerHandler,
26};
27
28#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
30pub struct FakeInstant {
31 pub offset: Duration,
33}
34
35impl crate::inspect::InspectableValue for FakeInstant {
36 fn record<I: crate::inspect::Inspector>(&self, name: &str, inspector: &mut I) {
37 inspector.record_uint(name, self.offset.as_nanos() as u64)
38 }
39}
40
41impl FakeInstant {
42 pub const LATEST: FakeInstant = FakeInstant { offset: Duration::MAX };
44
45 pub fn saturating_add(self, dur: Duration) -> FakeInstant {
47 FakeInstant { offset: self.offset.saturating_add(dur) }
48 }
49}
50
51impl From<Duration> for FakeInstant {
52 fn from(offset: Duration) -> FakeInstant {
53 FakeInstant { offset }
54 }
55}
56
57impl Instant for FakeInstant {
58 fn checked_duration_since(&self, earlier: FakeInstant) -> Option<Duration> {
59 self.offset.checked_sub(earlier.offset)
60 }
61
62 fn checked_add(&self, duration: Duration) -> Option<FakeInstant> {
63 self.offset.checked_add(duration).map(|offset| FakeInstant { offset })
64 }
65
66 fn saturating_add(&self, duration: Duration) -> Self {
67 FakeInstant { offset: self.offset.saturating_add(duration) }
68 }
69
70 fn checked_sub(&self, duration: Duration) -> Option<FakeInstant> {
71 self.offset.checked_sub(duration).map(|offset| FakeInstant { offset })
72 }
73}
74
75impl ops::Add<Duration> for FakeInstant {
76 type Output = FakeInstant;
77
78 fn add(self, dur: Duration) -> FakeInstant {
79 FakeInstant { offset: self.offset + dur }
80 }
81}
82
83impl ops::Sub<FakeInstant> for FakeInstant {
84 type Output = Duration;
85
86 fn sub(self, other: FakeInstant) -> Duration {
87 self.offset - other.offset
88 }
89}
90
91impl ops::Sub<Duration> for FakeInstant {
92 type Output = FakeInstant;
93
94 fn sub(self, dur: Duration) -> FakeInstant {
95 FakeInstant { offset: self.offset - dur }
96 }
97}
98
99impl Debug for FakeInstant {
100 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
101 write!(f, "{:?}", self.offset)
102 }
103}
104
105#[derive(Debug)]
107pub struct FakeAtomicInstant {
108 value: Mutex<FakeInstant>,
109}
110
111impl AtomicInstant<FakeInstant> for FakeAtomicInstant {
112 fn new(instant: FakeInstant) -> FakeAtomicInstant {
113 FakeAtomicInstant { value: Mutex::new(instant) }
114 }
115
116 fn load(&self, _ordering: Ordering) -> FakeInstant {
117 *self.value.lock()
118 }
119
120 fn store(&self, instant: FakeInstant, _ordering: Ordering) {
121 *self.value.lock() = instant
122 }
123
124 fn store_max(&self, instant: FakeInstant, _ordering: Ordering) {
125 let mut guard = self.value.lock();
126 if *guard < instant {
127 *guard = instant
128 }
129 }
130}
131
132#[derive(Default)]
135pub struct FakeInstantCtx {
136 pub time: FakeInstant,
138}
139
140impl FakeInstantCtx {
141 pub fn sleep(&mut self, dur: Duration) {
143 self.time.offset += dur;
144 }
145
146 pub fn sleep_until(&mut self, instant: FakeInstant) {
150 assert!(instant > self.time, "sleep until the past not allowed");
151 self.time = instant;
152 }
153}
154
155impl InstantBindingsTypes for FakeInstantCtx {
156 type Instant = FakeInstant;
157 type AtomicInstant = FakeAtomicInstant;
158}
159
160impl InstantContext for FakeInstantCtx {
161 fn now(&self) -> FakeInstant {
162 self.time
163 }
164}
165
166#[derive(Clone, Debug)]
171pub struct InstantAndData<D>(pub FakeInstant, pub D);
172
173impl<D> InstantAndData<D> {
174 pub fn new(time: FakeInstant, data: D) -> Self {
176 Self(time, data)
177 }
178}
179
180impl<D> Eq for InstantAndData<D> {}
181
182impl<D> PartialEq for InstantAndData<D> {
183 fn eq(&self, other: &Self) -> bool {
184 self.0 == other.0
185 }
186}
187
188impl<D> Ord for InstantAndData<D> {
189 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
190 other.0.cmp(&self.0)
191 }
192}
193
194impl<D> PartialOrd for InstantAndData<D> {
195 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
196 Some(self.cmp(other))
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct FakeTimer<Id> {
203 timer_id: usize,
204 pub dispatch_id: Id,
205}
206
207impl<Id> FakeTimer<Id> {
208 pub fn timer_id(&self) -> FakeTimerId {
210 FakeTimerId(Some(self.timer_id))
211 }
212
213 pub fn into_dispatch_and_timer_id(self) -> (Id, FakeTimerId) {
215 let Self { timer_id, dispatch_id } = self;
216 (dispatch_id, FakeTimerId(Some(timer_id)))
217 }
218}
219
220#[derive(PartialEq, Eq, Copy, Clone, Debug, Default)]
224pub struct FakeTimerId(Option<usize>);
225
226pub struct FakeTimerCtx<Id> {
228 pub instant: FakeInstantCtx,
230 pub timers: BinaryHeap<InstantAndData<FakeTimer<Id>>>,
232 next_timer_id: usize,
234}
235
236impl<Id> Default for FakeTimerCtx<Id> {
237 fn default() -> FakeTimerCtx<Id> {
238 FakeTimerCtx {
239 instant: FakeInstantCtx::default(),
240 timers: BinaryHeap::default(),
241 next_timer_id: 0,
242 }
243 }
244}
245
246impl<Id: Clone> FakeTimerCtx<Id> {
247 pub fn timers(&self) -> Vec<(FakeInstant, Id)> {
249 self.timers
250 .clone()
251 .into_sorted_vec()
252 .into_iter()
253 .map(|InstantAndData(i, FakeTimer { timer_id: _, dispatch_id })| (i, dispatch_id))
254 .collect()
255 }
256}
257
258impl<Id: Debug + Clone + Hash + Eq> FakeTimerCtx<Id> {
259 #[track_caller]
268 pub fn assert_timers_installed<I: IntoIterator<Item = (Id, FakeInstant)>>(&self, timers: I) {
269 self.assert_timers_installed_range(
270 timers.into_iter().map(|(id, instant)| (id, instant..=instant)),
271 );
272 }
273
274 #[track_caller]
280 pub fn assert_timers_installed_range<
281 R: ops::RangeBounds<FakeInstant> + Debug,
282 I: IntoIterator<Item = (Id, R)>,
283 >(
284 &self,
285 timers: I,
286 ) {
287 self.assert_timers_installed_inner(timers, true);
288 }
289
290 #[track_caller]
296 pub fn assert_some_timers_installed<I: IntoIterator<Item = (Id, FakeInstant)>>(
297 &self,
298 timers: I,
299 ) {
300 self.assert_some_timers_installed_range(
301 timers.into_iter().map(|(id, instant)| (id, instant..=instant)),
302 );
303 }
304
305 #[track_caller]
308 pub fn assert_some_timers_installed_range<
309 R: ops::RangeBounds<FakeInstant> + Debug,
310 I: IntoIterator<Item = (Id, R)>,
311 >(
312 &self,
313 timers: I,
314 ) {
315 self.assert_timers_installed_inner(timers, false);
316 }
317
318 #[track_caller]
324 pub fn assert_no_timers_installed(&self) {
325 self.assert_timers_installed([]);
326 }
327
328 #[track_caller]
329 fn assert_timers_installed_inner<
330 R: ops::RangeBounds<FakeInstant> + Debug,
331 I: IntoIterator<Item = (Id, R)>,
332 >(
333 &self,
334 timers: I,
335 exact: bool,
336 ) {
337 let mut timers = timers.into_iter().fold(HashMap::new(), |mut timers, (id, range)| {
338 assert_matches!(timers.insert(id, range), None);
339 timers
340 });
341
342 enum Error<Id, R: ops::RangeBounds<FakeInstant>> {
343 ExpectedButMissing { id: Id, range: R },
344 UnexpectedButPresent { id: Id, instant: FakeInstant },
345 UnexpectedInstant { id: Id, range: R, instant: FakeInstant },
346 }
347
348 let mut errors = Vec::new();
349
350 for InstantAndData(instant, FakeTimer { timer_id: _, dispatch_id: id }) in
353 self.timers.iter().cloned()
354 {
355 match timers.remove(&id) {
356 None => {
357 if exact {
358 errors.push(Error::UnexpectedButPresent { id, instant })
359 }
360 }
361 Some(range) => {
362 if !range.contains(&instant) {
363 errors.push(Error::UnexpectedInstant { id, range, instant })
364 }
365 }
366 }
367 }
368
369 errors.extend(timers.drain().map(|(id, range)| Error::ExpectedButMissing { id, range }));
372
373 if errors.len() > 0 {
374 let mut s = String::from("Unexpected timer contents:");
375 for err in errors {
376 s += &match err {
377 Error::ExpectedButMissing { id, range } => {
378 format!("\n\tMissing timer {:?} with deadline {:?}", id, range)
379 }
380 Error::UnexpectedButPresent { id, instant } => {
381 format!("\n\tUnexpected timer {:?} with deadline {:?}", id, instant)
382 }
383 Error::UnexpectedInstant { id, range, instant } => format!(
384 "\n\tTimer {:?} has unexpected deadline {:?} (wanted {:?})",
385 id, instant, range
386 ),
387 };
388 }
389 panic!("{}", s);
390 }
391 }
392}
393
394impl<Id: PartialEq> FakeTimerCtx<Id> {
395 fn cancel_timer_inner(&mut self, timer: &FakeTimer<Id>) -> Option<FakeInstant> {
396 let mut r: Option<FakeInstant> = None;
397 self.timers.retain(|InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
400 if timer.timer_id == *timer_id {
401 r = Some(*instant);
402 false
403 } else {
404 true
405 }
406 });
407 r
408 }
409}
410
411impl<Id> InstantBindingsTypes for FakeTimerCtx<Id> {
412 type Instant = FakeInstant;
413 type AtomicInstant = FakeAtomicInstant;
414}
415
416impl<Id> InstantContext for FakeTimerCtx<Id> {
417 fn now(&self) -> FakeInstant {
418 self.instant.now()
419 }
420}
421
422impl<Id: Debug + Clone + Send + Sync> TimerBindingsTypes for FakeTimerCtx<Id> {
423 type Timer = FakeTimer<Id>;
424 type DispatchId = Id;
425 type UniqueTimerId = FakeTimerId;
426}
427
428impl<Id: PartialEq + Debug + Clone + Send + Sync> TimerContext for FakeTimerCtx<Id> {
429 fn new_timer(&mut self, dispatch_id: Self::DispatchId) -> Self::Timer {
430 let timer_id = self.next_timer_id;
431 self.next_timer_id += 1;
432 FakeTimer { timer_id, dispatch_id }
433 }
434
435 fn schedule_timer_instant(
436 &mut self,
437 time: Self::Instant,
438 timer: &mut Self::Timer,
439 ) -> Option<Self::Instant> {
440 let ret = self.cancel_timer_inner(timer);
441 self.timers.push(InstantAndData::new(time, timer.clone()));
442 ret
443 }
444
445 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
446 self.cancel_timer_inner(timer)
447 }
448
449 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
450 self.timers.iter().find_map(
451 |InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
452 (timer.timer_id == *timer_id).then_some(*instant)
453 },
454 )
455 }
456
457 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
458 timer.timer_id()
459 }
460}
461
462pub trait WithFakeTimerContext<TimerId> {
464 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O;
466
467 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(&mut self, f: F)
469 -> O;
470}
471
472impl<TimerId> WithFakeTimerContext<TimerId> for FakeTimerCtx<TimerId> {
473 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
474 f(self)
475 }
476
477 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
478 &mut self,
479 f: F,
480 ) -> O {
481 f(self)
482 }
483}
484
485impl<TimerId, CC, BC> WithFakeTimerContext<TimerId> for CtxPair<CC, BC>
486where
487 BC: WithFakeTimerContext<TimerId>,
488{
489 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
490 self.bindings_ctx.with_fake_timer_ctx(f)
491 }
492
493 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
494 &mut self,
495 f: F,
496 ) -> O {
497 self.bindings_ctx.with_fake_timer_ctx_mut(f)
498 }
499}
500
501pub trait FakeTimerCtxExt<Id>: Sized + TimerBindingsTypes {
503 fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id>;
508
509 fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
518 &mut self,
519 instant: FakeInstant,
520 handler: &mut H,
521 ) -> Vec<Id>;
522
523 fn trigger_timers_for<H: TimerHandler<Self, Id>>(
528 &mut self,
529 duration: Duration,
530 handler: &mut H,
531 ) -> Vec<Id>;
532
533 #[track_caller]
545 fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
546 &mut self,
547 timers: I,
548 handler: &mut H,
549 ) where
550 Id: Debug + Hash + Eq;
551
552 fn trigger_timers_until_and_expect_unordered<
557 I: IntoIterator<Item = Id>,
558 H: TimerHandler<Self, Id>,
559 >(
560 &mut self,
561 instant: FakeInstant,
562 timers: I,
563 handler: &mut H,
564 ) where
565 Id: Debug + Hash + Eq;
566
567 fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
572 &mut self,
573 duration: Duration,
574 timers: I,
575 handler: &mut H,
576 ) where
577 Id: Debug + Hash + Eq;
578}
579
580impl<Id: Clone, Ctx: WithFakeTimerContext<Id> + TimerBindingsTypes<UniqueTimerId = FakeTimerId>>
583 FakeTimerCtxExt<Id> for Ctx
584{
585 fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id> {
590 self.with_fake_timer_ctx_mut(|timers| {
591 timers.timers.pop().map(|InstantAndData(t, id)| {
592 timers.instant.time = t;
593 id
594 })
595 })
596 .map(|fake_timer| {
597 let (dispatch_id, timer_id) = fake_timer.into_dispatch_and_timer_id();
598 handler.handle_timer(self, dispatch_id.clone(), timer_id);
599 dispatch_id
600 })
601 }
602
603 fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
612 &mut self,
613 instant: FakeInstant,
614 handler: &mut H,
615 ) -> Vec<Id> {
616 assert!(instant >= self.with_fake_timer_ctx(|ctx| ctx.now()));
617 let mut timers = Vec::new();
618
619 while self.with_fake_timer_ctx_mut(|ctx| {
620 ctx.timers.peek().map(|InstantAndData(i, _id)| i <= &instant).unwrap_or(false)
621 }) {
622 timers.push(self.trigger_next_timer(handler).unwrap())
623 }
624
625 self.with_fake_timer_ctx_mut(|ctx| {
626 assert!(ctx.now() <= instant);
627 ctx.instant.time = instant;
628 });
629
630 timers
631 }
632
633 fn trigger_timers_for<H: TimerHandler<Self, Id>>(
638 &mut self,
639 duration: Duration,
640 handler: &mut H,
641 ) -> Vec<Id> {
642 let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
643 self.trigger_timers_until_instant(instant, handler)
647 }
648
649 #[track_caller]
661 fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
662 &mut self,
663 timers: I,
664 handler: &mut H,
665 ) where
666 Id: Debug + Hash + Eq,
667 {
668 let mut timers = RefCountedHashSet::from_iter(timers);
669
670 for _ in 0..timers.len() {
671 let id = self.trigger_next_timer(handler).expect("ran out of timers to trigger");
672 match timers.remove(id.clone()) {
673 RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
674 RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
675 }
676 }
677
678 if timers.len() > 0 {
679 let mut s = String::from("Expected timers did not trigger:");
680 for (id, count) in timers.iter_counts() {
681 s += &format!("\n\t{count}x {id:?}");
682 }
683 panic!("{}", s);
684 }
685 }
686
687 fn trigger_timers_until_and_expect_unordered<
693 I: IntoIterator<Item = Id>,
694 H: TimerHandler<Self, Id>,
695 >(
696 &mut self,
697 instant: FakeInstant,
698 timers: I,
699 handler: &mut H,
700 ) where
701 Id: Debug + Hash + Eq,
702 {
703 let mut timers = RefCountedHashSet::from_iter(timers);
704
705 let triggered_timers = self.trigger_timers_until_instant(instant, handler);
706
707 for id in triggered_timers {
708 match timers.remove(id.clone()) {
709 RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
710 RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
711 }
712 }
713
714 if timers.len() > 0 {
715 let mut s = String::from("Expected timers did not trigger:");
716 for (id, count) in timers.iter_counts() {
717 s += &format!("\n\t{count}x {id:?}");
718 }
719 panic!("{}", s);
720 }
721 }
722
723 fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
729 &mut self,
730 duration: Duration,
731 timers: I,
732 handler: &mut H,
733 ) where
734 Id: Debug + Hash + Eq,
735 {
736 let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
737 self.trigger_timers_until_and_expect_unordered(instant, timers, handler);
738 }
739}
740
741#[cfg(test)]
742mod tests {
743 use super::*;
744
745 use crate::HandleableTimer;
746
747 use alloc::vec;
748
749 const ONE_SEC: Duration = Duration::from_secs(1);
750 const ONE_SEC_INSTANT: FakeInstant = FakeInstant { offset: ONE_SEC };
751
752 #[derive(Debug, Eq, PartialEq, Clone, Hash)]
753 struct TimerId(usize);
754 #[derive(Default)]
755 struct CoreCtx(Vec<(TimerId, FakeInstant)>);
756
757 impl CoreCtx {
758 fn take(&mut self) -> Vec<(TimerId, FakeInstant)> {
759 core::mem::take(&mut self.0)
760 }
761 }
762
763 impl HandleableTimer<CoreCtx, FakeTimerCtx<Self>> for TimerId {
764 fn handle(
765 self,
766 CoreCtx(expired): &mut CoreCtx,
767 bindings_ctx: &mut FakeTimerCtx<Self>,
768 _: FakeTimerId,
769 ) {
770 expired.push((self, bindings_ctx.now()))
771 }
772 }
773
774 #[test]
775 fn instant_and_data() {
776 let mut heap = BinaryHeap::<InstantAndData<usize>>::new();
779 let now = FakeInstant::default();
780
781 fn new_data(time: FakeInstant, id: usize) -> InstantAndData<usize> {
782 InstantAndData::new(time, id)
783 }
784
785 heap.push(new_data(now + Duration::from_secs(1), 1));
786 heap.push(new_data(now + Duration::from_secs(2), 2));
787
788 assert_eq!(heap.pop().unwrap().1, 1);
790 assert_eq!(heap.pop().unwrap().1, 2);
791 assert_eq!(heap.pop(), None);
792
793 heap.push(new_data(now + Duration::from_secs(1), 1));
794 heap.push(new_data(now + Duration::from_secs(1), 1));
795
796 assert_eq!(heap.pop().unwrap().1, 1);
798 assert_eq!(heap.pop().unwrap().1, 1);
799 assert_eq!(heap.pop(), None);
800 }
801
802 #[test]
803 fn fake_timer_context() {
804 let mut core_ctx = CoreCtx::default();
805 let mut bindings_ctx = FakeTimerCtx::<TimerId>::default();
806
807 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
810 assert_eq!(core_ctx.take(), vec![]);
811
812 let mut timer0 = bindings_ctx.new_timer(TimerId(0));
813 let mut timer1 = bindings_ctx.new_timer(TimerId(1));
814 let mut timer2 = bindings_ctx.new_timer(TimerId(2));
815
816 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
818
819 assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
820
821 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0).unwrap(), ONE_SEC_INSTANT);
823
824 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), Some(TimerId(0)));
825 assert_eq!(core_ctx.take(), vec![(TimerId(0), ONE_SEC_INSTANT)]);
826
827 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
830
831 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
833
834 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
837 assert_eq!(core_ctx.take(), vec![]);
838
839 bindings_ctx.instant.time = Default::default();
841
842 assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
844 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
845 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
846 assert_eq!(core_ctx.take(), vec![]);
847
848 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
851 assert_eq!(
852 bindings_ctx.schedule_timer(ONE_SEC, &mut timer0),
853 Some(Duration::from_secs(0).into())
854 );
855 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
856
857 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
860 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(1), &mut timer1), None);
861 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer2), None);
862 assert_eq!(
863 bindings_ctx.trigger_timers_until_instant(ONE_SEC_INSTANT, &mut core_ctx),
864 vec![TimerId(0), TimerId(1)],
865 );
866
867 assert_eq!(
869 core_ctx.take(),
870 vec![
871 (TimerId(0), FakeInstant::from(Duration::from_secs(0))),
872 (TimerId(1), ONE_SEC_INSTANT)
873 ]
874 );
875
876 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), None);
878 assert_eq!(bindings_ctx.cancel_timer(&mut timer1), None);
879
880 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
882
883 assert_eq!(
885 bindings_ctx.cancel_timer(&mut timer2),
886 Some(FakeInstant::from(Duration::from_secs(2)))
887 );
888 }
889
890 #[test]
891 fn trigger_timers_until_and_expect_unordered() {
892 let mut core_ctx = CoreCtx::default();
895 let mut bindings_ctx = FakeTimerCtx::default();
896 let mut timer0 = bindings_ctx.new_timer(TimerId(0));
897 let mut timer1 = bindings_ctx.new_timer(TimerId(1));
898 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
899 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer1), None);
900 bindings_ctx.trigger_timers_until_and_expect_unordered(
901 ONE_SEC_INSTANT,
902 vec![TimerId(0)],
903 &mut core_ctx,
904 );
905 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
906 }
907}