netstack3_base/testutil/
fake_bindings.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A shareable fake bindings context.
6
7use alloc::vec::Vec;
8use core::convert::Infallible as Never;
9use core::fmt::Debug;
10
11use crate::sync::DynDebugReferences;
12use crate::testutil::{
13    AlwaysDefaultsSettingsContext, FakeAtomicInstant, FakeCryptoRng, FakeEventCtx, FakeFrameCtx,
14    FakeInstant, FakeTimerCtx, WithFakeTimerContext,
15};
16use crate::{
17    ContextProvider, DeferredResourceRemovalContext, EventContext, InstantBindingsTypes,
18    InstantContext, MatcherBindingsTypes, ReferenceNotifiers, RngContext, TimerBindingsTypes,
19    TimerContext,
20};
21
22/// A test helper used to provide an implementation of a bindings context.
23pub struct FakeBindingsCtx<TimerId, Event: Debug, State, FrameMeta> {
24    /// Provides [`RngContext`].
25    pub rng: FakeCryptoRng,
26    /// Provides [`TimerContext`].
27    pub timers: FakeTimerCtx<TimerId>,
28    /// Provides [`EventContext`].
29    pub events: FakeEventCtx<Event>,
30    /// Provides [`SendFrameContext`].
31    pub frames: FakeFrameCtx<FrameMeta>,
32    /// Generic state used by specific tests.
33    pub state: State,
34}
35
36impl<TimerId, Event: Debug, State, FrameMeta> ContextProvider
37    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
38{
39    type Context = Self;
40    fn context(&mut self) -> &mut Self::Context {
41        self
42    }
43}
44
45impl<TimerId, Event: Debug, State: Default, FrameMeta> Default
46    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
47{
48    fn default() -> Self {
49        Self {
50            rng: FakeCryptoRng::new_xorshift(0),
51            timers: FakeTimerCtx::default(),
52            events: FakeEventCtx::default(),
53            frames: FakeFrameCtx::default(),
54            state: Default::default(),
55        }
56    }
57}
58
59impl<TimerId, Event: Debug, State, FrameMeta> FakeBindingsCtx<TimerId, Event, State, FrameMeta> {
60    /// Seed the testing RNG with a specific value.
61    pub fn seed_rng(&mut self, seed: u128) {
62        self.rng = FakeCryptoRng::new_xorshift(seed);
63    }
64
65    /// Takes all the accumulated events from the [`FakeEventCtx`].
66    pub fn take_events(&mut self) -> Vec<Event> {
67        self.events.take()
68    }
69}
70
71impl<TimerId, Event: Debug, State, FrameMeta> RngContext
72    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
73{
74    type Rng<'a>
75        = FakeCryptoRng
76    where
77        Self: 'a;
78
79    fn rng(&mut self) -> Self::Rng<'_> {
80        self.rng.clone()
81    }
82}
83
84impl<TimerId, Event: Debug, State, FrameMeta> InstantBindingsTypes
85    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
86{
87    type Instant = FakeInstant;
88    type AtomicInstant = FakeAtomicInstant;
89}
90
91impl<TimerId, Event: Debug, State, FrameMeta> InstantContext
92    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
93{
94    fn now(&self) -> Self::Instant {
95        self.timers.now()
96    }
97}
98
99impl<Id: Debug + PartialEq + Clone + Send + Sync, Event: Debug, State, FrameMeta> TimerBindingsTypes
100    for FakeBindingsCtx<Id, Event, State, FrameMeta>
101{
102    type Timer = <FakeTimerCtx<Id> as TimerBindingsTypes>::Timer;
103    type DispatchId = <FakeTimerCtx<Id> as TimerBindingsTypes>::DispatchId;
104    type UniqueTimerId = <FakeTimerCtx<Id> as TimerBindingsTypes>::UniqueTimerId;
105}
106
107impl<Id: Debug + PartialEq + Clone + Send + Sync, Event: Debug, State, FrameMeta> TimerContext
108    for FakeBindingsCtx<Id, Event, State, FrameMeta>
109{
110    fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
111        self.timers.new_timer(id)
112    }
113
114    fn schedule_timer_instant(
115        &mut self,
116        time: Self::Instant,
117        timer: &mut Self::Timer,
118    ) -> Option<Self::Instant> {
119        self.timers.schedule_timer_instant(time, timer)
120    }
121
122    fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
123        self.timers.cancel_timer(timer)
124    }
125
126    fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
127        self.timers.scheduled_instant(timer)
128    }
129
130    fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
131        self.timers.unique_timer_id(timer)
132    }
133}
134
135impl<Id, Event: Debug, State, FrameMeta> EventContext<Event>
136    for FakeBindingsCtx<Id, Event, State, FrameMeta>
137{
138    fn on_event(&mut self, event: Event) {
139        self.events.on_event(event)
140    }
141}
142
143impl<Id, Event: Debug, State, FrameMeta> ReferenceNotifiers
144    for FakeBindingsCtx<Id, Event, State, FrameMeta>
145{
146    type ReferenceReceiver<T: 'static> = Never;
147
148    type ReferenceNotifier<T: Send + 'static> = Never;
149
150    fn new_reference_notifier<T: Send + 'static>(
151        debug_references: DynDebugReferences,
152    ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
153        // NB: We don't want deferred destruction in core tests. These are
154        // always single-threaded and single-task, and we want to encourage
155        // explicit cleanup.
156        panic!(
157            "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
158            debug_references={debug_references:?}",
159            core::any::type_name::<T>()
160        );
161    }
162}
163
164impl<Id, Event: Debug, State, FrameMeta> DeferredResourceRemovalContext
165    for FakeBindingsCtx<Id, Event, State, FrameMeta>
166{
167    fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
168        match receiver {}
169    }
170}
171
172impl<TimerId, Event: Debug, State, FrameMeta> WithFakeTimerContext<TimerId>
173    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
174{
175    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
176        f(&self.timers)
177    }
178
179    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
180        &mut self,
181        f: F,
182    ) -> O {
183        f(&mut self.timers)
184    }
185}
186
187impl<TimerId, Event: Debug, State, FrameMeta> AlwaysDefaultsSettingsContext
188    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
189{
190}
191
192impl<TimerId: Debug, Event: Debug, State, FrameMeta> MatcherBindingsTypes
193    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
194{
195    type DeviceClass = ();
196}