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> FakeTimerCtx<Id> {
395 pub fn pop_next_timer_and_advance_time(&mut self) -> Option<Id> {
398 let InstantAndData(instant, timer) = self.timers.pop()?;
399 assert!(instant >= self.instant.time);
400 self.instant.time = instant;
401 Some(timer.dispatch_id)
402 }
403}
404
405impl<Id: PartialEq> FakeTimerCtx<Id> {
406 fn cancel_timer_inner(&mut self, timer: &FakeTimer<Id>) -> Option<FakeInstant> {
407 let mut r: Option<FakeInstant> = None;
408 self.timers.retain(|InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
411 if timer.timer_id == *timer_id {
412 r = Some(*instant);
413 false
414 } else {
415 true
416 }
417 });
418 r
419 }
420}
421
422impl<Id> InstantBindingsTypes for FakeTimerCtx<Id> {
423 type Instant = FakeInstant;
424 type AtomicInstant = FakeAtomicInstant;
425}
426
427impl<Id> InstantContext for FakeTimerCtx<Id> {
428 fn now(&self) -> FakeInstant {
429 self.instant.now()
430 }
431}
432
433impl<Id: Debug + Clone + Send + Sync> TimerBindingsTypes for FakeTimerCtx<Id> {
434 type Timer = FakeTimer<Id>;
435 type DispatchId = Id;
436 type UniqueTimerId = FakeTimerId;
437}
438
439impl<Id: PartialEq + Debug + Clone + Send + Sync> TimerContext for FakeTimerCtx<Id> {
440 fn new_timer(&mut self, dispatch_id: Self::DispatchId) -> Self::Timer {
441 let timer_id = self.next_timer_id;
442 self.next_timer_id += 1;
443 FakeTimer { timer_id, dispatch_id }
444 }
445
446 fn schedule_timer_instant(
447 &mut self,
448 time: Self::Instant,
449 timer: &mut Self::Timer,
450 ) -> Option<Self::Instant> {
451 let ret = self.cancel_timer_inner(timer);
452 self.timers.push(InstantAndData::new(time, timer.clone()));
453 ret
454 }
455
456 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
457 self.cancel_timer_inner(timer)
458 }
459
460 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
461 self.timers.iter().find_map(
462 |InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
463 (timer.timer_id == *timer_id).then_some(*instant)
464 },
465 )
466 }
467
468 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
469 timer.timer_id()
470 }
471}
472
473pub trait WithFakeTimerContext<TimerId> {
475 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O;
477
478 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(&mut self, f: F)
480 -> O;
481}
482
483impl<TimerId> WithFakeTimerContext<TimerId> for FakeTimerCtx<TimerId> {
484 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
485 f(self)
486 }
487
488 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
489 &mut self,
490 f: F,
491 ) -> O {
492 f(self)
493 }
494}
495
496impl<TimerId, CC, BC> WithFakeTimerContext<TimerId> for CtxPair<CC, BC>
497where
498 BC: WithFakeTimerContext<TimerId>,
499{
500 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
501 self.bindings_ctx.with_fake_timer_ctx(f)
502 }
503
504 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
505 &mut self,
506 f: F,
507 ) -> O {
508 self.bindings_ctx.with_fake_timer_ctx_mut(f)
509 }
510}
511
512pub trait FakeTimerCtxExt<Id>: Sized + TimerBindingsTypes {
514 fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id>;
519
520 fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
529 &mut self,
530 instant: FakeInstant,
531 handler: &mut H,
532 ) -> Vec<Id>;
533
534 fn trigger_timers_for<H: TimerHandler<Self, Id>>(
539 &mut self,
540 duration: Duration,
541 handler: &mut H,
542 ) -> Vec<Id>;
543
544 #[track_caller]
556 fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
557 &mut self,
558 timers: I,
559 handler: &mut H,
560 ) where
561 Id: Debug + Hash + Eq;
562
563 fn trigger_timers_until_and_expect_unordered<
568 I: IntoIterator<Item = Id>,
569 H: TimerHandler<Self, Id>,
570 >(
571 &mut self,
572 instant: FakeInstant,
573 timers: I,
574 handler: &mut H,
575 ) where
576 Id: Debug + Hash + Eq;
577
578 fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
583 &mut self,
584 duration: Duration,
585 timers: I,
586 handler: &mut H,
587 ) where
588 Id: Debug + Hash + Eq;
589}
590
591impl<Id: Clone, Ctx: WithFakeTimerContext<Id> + TimerBindingsTypes<UniqueTimerId = FakeTimerId>>
594 FakeTimerCtxExt<Id> for Ctx
595{
596 fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id> {
601 self.with_fake_timer_ctx_mut(|timers| {
602 timers.timers.pop().map(|InstantAndData(t, id)| {
603 timers.instant.time = t;
604 id
605 })
606 })
607 .map(|fake_timer| {
608 let (dispatch_id, timer_id) = fake_timer.into_dispatch_and_timer_id();
609 handler.handle_timer(self, dispatch_id.clone(), timer_id);
610 dispatch_id
611 })
612 }
613
614 fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
623 &mut self,
624 instant: FakeInstant,
625 handler: &mut H,
626 ) -> Vec<Id> {
627 assert!(instant >= self.with_fake_timer_ctx(|ctx| ctx.now()));
628 let mut timers = Vec::new();
629
630 while self.with_fake_timer_ctx_mut(|ctx| {
631 ctx.timers.peek().map(|InstantAndData(i, _id)| i <= &instant).unwrap_or(false)
632 }) {
633 timers.push(self.trigger_next_timer(handler).unwrap())
634 }
635
636 self.with_fake_timer_ctx_mut(|ctx| {
637 assert!(ctx.now() <= instant);
638 ctx.instant.time = instant;
639 });
640
641 timers
642 }
643
644 fn trigger_timers_for<H: TimerHandler<Self, Id>>(
649 &mut self,
650 duration: Duration,
651 handler: &mut H,
652 ) -> Vec<Id> {
653 let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
654 self.trigger_timers_until_instant(instant, handler)
658 }
659
660 #[track_caller]
672 fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
673 &mut self,
674 timers: I,
675 handler: &mut H,
676 ) where
677 Id: Debug + Hash + Eq,
678 {
679 let mut timers = RefCountedHashSet::from_iter(timers);
680
681 for _ in 0..timers.len() {
682 let id = self.trigger_next_timer(handler).expect("ran out of timers to trigger");
683 match timers.remove(id.clone()) {
684 RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
685 RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
686 }
687 }
688
689 if timers.len() > 0 {
690 let mut s = String::from("Expected timers did not trigger:");
691 for (id, count) in timers.iter_counts() {
692 s += &format!("\n\t{count}x {id:?}");
693 }
694 panic!("{}", s);
695 }
696 }
697
698 fn trigger_timers_until_and_expect_unordered<
704 I: IntoIterator<Item = Id>,
705 H: TimerHandler<Self, Id>,
706 >(
707 &mut self,
708 instant: FakeInstant,
709 timers: I,
710 handler: &mut H,
711 ) where
712 Id: Debug + Hash + Eq,
713 {
714 let mut timers = RefCountedHashSet::from_iter(timers);
715
716 let triggered_timers = self.trigger_timers_until_instant(instant, handler);
717
718 for id in triggered_timers {
719 match timers.remove(id.clone()) {
720 RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
721 RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
722 }
723 }
724
725 if timers.len() > 0 {
726 let mut s = String::from("Expected timers did not trigger:");
727 for (id, count) in timers.iter_counts() {
728 s += &format!("\n\t{count}x {id:?}");
729 }
730 panic!("{}", s);
731 }
732 }
733
734 fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
740 &mut self,
741 duration: Duration,
742 timers: I,
743 handler: &mut H,
744 ) where
745 Id: Debug + Hash + Eq,
746 {
747 let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
748 self.trigger_timers_until_and_expect_unordered(instant, timers, handler);
749 }
750}
751
752#[cfg(test)]
753mod tests {
754 use super::*;
755
756 use crate::HandleableTimer;
757
758 use alloc::vec;
759
760 const ONE_SEC: Duration = Duration::from_secs(1);
761 const ONE_SEC_INSTANT: FakeInstant = FakeInstant { offset: ONE_SEC };
762
763 #[derive(Debug, Eq, PartialEq, Clone, Hash)]
764 struct TimerId(usize);
765 #[derive(Default)]
766 struct CoreCtx(Vec<(TimerId, FakeInstant)>);
767
768 impl CoreCtx {
769 fn take(&mut self) -> Vec<(TimerId, FakeInstant)> {
770 core::mem::take(&mut self.0)
771 }
772 }
773
774 impl HandleableTimer<CoreCtx, FakeTimerCtx<Self>> for TimerId {
775 fn handle(
776 self,
777 CoreCtx(expired): &mut CoreCtx,
778 bindings_ctx: &mut FakeTimerCtx<Self>,
779 _: FakeTimerId,
780 ) {
781 expired.push((self, bindings_ctx.now()))
782 }
783 }
784
785 #[test]
786 fn instant_and_data() {
787 let mut heap = BinaryHeap::<InstantAndData<usize>>::new();
790 let now = FakeInstant::default();
791
792 fn new_data(time: FakeInstant, id: usize) -> InstantAndData<usize> {
793 InstantAndData::new(time, id)
794 }
795
796 heap.push(new_data(now + Duration::from_secs(1), 1));
797 heap.push(new_data(now + Duration::from_secs(2), 2));
798
799 assert_eq!(heap.pop().unwrap().1, 1);
801 assert_eq!(heap.pop().unwrap().1, 2);
802 assert_eq!(heap.pop(), None);
803
804 heap.push(new_data(now + Duration::from_secs(1), 1));
805 heap.push(new_data(now + Duration::from_secs(1), 1));
806
807 assert_eq!(heap.pop().unwrap().1, 1);
809 assert_eq!(heap.pop().unwrap().1, 1);
810 assert_eq!(heap.pop(), None);
811 }
812
813 #[test]
814 fn fake_timer_context() {
815 let mut core_ctx = CoreCtx::default();
816 let mut bindings_ctx = FakeTimerCtx::<TimerId>::default();
817
818 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
821 assert_eq!(core_ctx.take(), vec![]);
822
823 let mut timer0 = bindings_ctx.new_timer(TimerId(0));
824 let mut timer1 = bindings_ctx.new_timer(TimerId(1));
825 let mut timer2 = bindings_ctx.new_timer(TimerId(2));
826
827 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
829
830 assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
831
832 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0).unwrap(), ONE_SEC_INSTANT);
834
835 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), Some(TimerId(0)));
836 assert_eq!(core_ctx.take(), vec![(TimerId(0), ONE_SEC_INSTANT)]);
837
838 assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
841
842 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
844
845 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
848 assert_eq!(core_ctx.take(), vec![]);
849
850 bindings_ctx.instant.time = Default::default();
852
853 assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
855 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
856 assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
857 assert_eq!(core_ctx.take(), vec![]);
858
859 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
862 assert_eq!(
863 bindings_ctx.schedule_timer(ONE_SEC, &mut timer0),
864 Some(Duration::from_secs(0).into())
865 );
866 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
867
868 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
871 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(1), &mut timer1), None);
872 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer2), None);
873 assert_eq!(
874 bindings_ctx.trigger_timers_until_instant(ONE_SEC_INSTANT, &mut core_ctx),
875 vec![TimerId(0), TimerId(1)],
876 );
877
878 assert_eq!(
880 core_ctx.take(),
881 vec![
882 (TimerId(0), FakeInstant::from(Duration::from_secs(0))),
883 (TimerId(1), ONE_SEC_INSTANT)
884 ]
885 );
886
887 assert_eq!(bindings_ctx.cancel_timer(&mut timer0), None);
889 assert_eq!(bindings_ctx.cancel_timer(&mut timer1), None);
890
891 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
893
894 assert_eq!(
896 bindings_ctx.cancel_timer(&mut timer2),
897 Some(FakeInstant::from(Duration::from_secs(2)))
898 );
899 }
900
901 #[test]
902 fn trigger_timers_until_and_expect_unordered() {
903 let mut core_ctx = CoreCtx::default();
906 let mut bindings_ctx = FakeTimerCtx::default();
907 let mut timer0 = bindings_ctx.new_timer(TimerId(0));
908 let mut timer1 = bindings_ctx.new_timer(TimerId(1));
909 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
910 assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer1), None);
911 bindings_ctx.trigger_timers_until_and_expect_unordered(
912 ONE_SEC_INSTANT,
913 vec![TimerId(0)],
914 &mut core_ctx,
915 );
916 assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
917 }
918}