Skip to main content

thedes_tui_core/audio/device/
mock.rs

1use std::{borrow::Cow, collections::VecDeque, mem, sync::Arc};
2
3use crate::audio::device::{
4    AudioDevice,
5    AudioSinkDevice,
6    CheckPlayStatusError,
7    ClearSinkError,
8    OpenSinkError,
9    PauseSinkError,
10    PlayNowError,
11    ResumeSinkError,
12    SetVolumeError,
13};
14
15#[derive(Debug)]
16struct State {
17    open_sink_results:
18        VecDeque<Result<Box<dyn AudioSinkDevice>, OpenSinkError>>,
19    open_sink_log: Option<u32>,
20    device_open: bool,
21}
22
23impl State {
24    pub fn new() -> Self {
25        Self {
26            open_sink_results: VecDeque::new(),
27            device_open: false,
28            open_sink_log: None,
29        }
30    }
31
32    pub fn register_sink(&mut self) -> AudioSinkDeviceMock {
33        let sink_mock = AudioSinkDeviceMock::new();
34        self.register_open_sink_results([Ok(sink_mock.open())]);
35        sink_mock
36    }
37
38    pub fn register_open_sink_results(
39        &mut self,
40        results: impl IntoIterator<
41            Item = Result<Box<dyn AudioSinkDevice>, OpenSinkError>,
42        >,
43    ) {
44        self.open_sink_results.extend(results);
45    }
46
47    pub fn enable_open_sink_log(&mut self) {
48        self.open_sink_log = Some(0);
49    }
50
51    pub fn disable_open_sink_log(&mut self) {
52        self.open_sink_log = None;
53    }
54
55    pub fn take_open_sink_log(&mut self) -> Option<u32> {
56        self.open_sink_log.as_mut().map(mem::take)
57    }
58
59    pub fn open_sink(
60        &mut self,
61    ) -> Result<Box<dyn AudioSinkDevice>, OpenSinkError> {
62        if let Some(log) = self.open_sink_log.as_mut() {
63            *log += 1;
64        }
65        self.open_sink_results
66            .pop_front()
67            .unwrap_or_else(|| Ok(AudioSinkDeviceMock::new().open()))
68    }
69
70    pub fn mark_device_open(&mut self) -> bool {
71        mem::replace(&mut self.device_open, true)
72    }
73}
74
75#[derive(Debug)]
76struct SinkState {
77    play_results: VecDeque<Result<(), PlayNowError>>,
78    set_volume_results: VecDeque<Result<(), SetVolumeError>>,
79    pause_results: VecDeque<Result<(), PauseSinkError>>,
80    resume_results: VecDeque<Result<(), ResumeSinkError>>,
81    clear_results: VecDeque<Result<(), ClearSinkError>>,
82    is_playing_results: VecDeque<Result<(), CheckPlayStatusError>>,
83    play_log: Option<Vec<Cow<'static, [u8]>>>,
84    set_volume_log: Option<Vec<f32>>,
85    sink_open: bool,
86    playing: bool,
87}
88
89impl SinkState {
90    pub fn new() -> Self {
91        Self {
92            play_results: VecDeque::new(),
93            set_volume_results: VecDeque::new(),
94            is_playing_results: VecDeque::new(),
95            pause_results: VecDeque::new(),
96            resume_results: VecDeque::new(),
97            clear_results: VecDeque::new(),
98            play_log: None,
99            set_volume_log: None,
100            sink_open: false,
101            playing: false,
102        }
103    }
104
105    pub fn register_play_results(
106        &mut self,
107        results: impl IntoIterator<Item = Result<(), PlayNowError>>,
108    ) {
109        self.play_results.extend(results);
110    }
111
112    pub fn register_set_volume_results(
113        &mut self,
114        results: impl IntoIterator<Item = Result<(), SetVolumeError>>,
115    ) {
116        self.set_volume_results.extend(results);
117    }
118
119    pub fn register_pause_results(
120        &mut self,
121        results: impl IntoIterator<Item = Result<(), PauseSinkError>>,
122    ) {
123        self.pause_results.extend(results);
124    }
125
126    pub fn register_resume_results(
127        &mut self,
128        results: impl IntoIterator<Item = Result<(), ResumeSinkError>>,
129    ) {
130        self.resume_results.extend(results);
131    }
132
133    pub fn register_clear_results(
134        &mut self,
135        results: impl IntoIterator<Item = Result<(), ClearSinkError>>,
136    ) {
137        self.clear_results.extend(results);
138    }
139
140    pub fn play_now(
141        &mut self,
142        bytes: Cow<'static, [u8]>,
143    ) -> Result<(), PlayNowError> {
144        if let Some(play_log) = self.play_log.as_mut() {
145            play_log.push(bytes);
146        }
147        let result = self.play_results.pop_front().unwrap_or(Ok(()));
148        if result.is_ok() {
149            self.playing = true;
150        }
151        result
152    }
153
154    pub fn pause(&mut self) -> Result<(), PauseSinkError> {
155        self.pause_results.pop_front().unwrap_or(Ok(()))?;
156        self.playing = false;
157        Ok(())
158    }
159
160    pub fn resume(&mut self) -> Result<(), ResumeSinkError> {
161        self.resume_results.pop_front().unwrap_or(Ok(()))?;
162        self.playing = true;
163        Ok(())
164    }
165
166    pub fn clear(&mut self) -> Result<(), ClearSinkError> {
167        self.clear_results.pop_front().unwrap_or(Ok(()))?;
168        self.playing = false;
169        Ok(())
170    }
171
172    pub fn force_pause(&mut self) {
173        self.playing = false;
174    }
175
176    pub fn force_resume(&mut self) {
177        self.playing = true;
178    }
179
180    pub fn is_playing(&mut self) -> Result<bool, CheckPlayStatusError> {
181        match self.is_playing_results.pop_front() {
182            Some(Ok(())) | None => Ok(self.playing),
183            Some(Err(e)) => Err(e),
184        }
185    }
186
187    pub fn set_volume(&mut self, volume: f32) -> Result<(), SetVolumeError> {
188        if let Some(set_volume_log) = self.set_volume_log.as_mut() {
189            set_volume_log.push(volume);
190        }
191        self.set_volume_results.pop_front().unwrap_or(Ok(()))
192    }
193
194    pub fn enable_play_log(&mut self) {
195        if self.play_log.is_none() {
196            self.play_log = Some(Vec::new());
197        }
198    }
199
200    pub fn disable_play_log(&mut self) -> Option<Vec<Cow<'static, [u8]>>> {
201        self.play_log.take()
202    }
203
204    pub fn take_play_log(&mut self) -> Option<Vec<Cow<'static, [u8]>>> {
205        self.play_log.as_mut().map(mem::take)
206    }
207
208    pub fn enable_set_volume_log(&mut self) {
209        if self.set_volume_log.is_none() {
210            self.set_volume_log = Some(Vec::new());
211        }
212    }
213
214    pub fn disable_set_volume_log(&mut self) -> Option<Vec<f32>> {
215        self.set_volume_log.take()
216    }
217
218    pub fn take_set_volume_log(&mut self) -> Option<Vec<f32>> {
219        self.set_volume_log.as_mut().map(mem::take)
220    }
221
222    pub fn mark_sink_open(&mut self) -> bool {
223        mem::replace(&mut self.sink_open, true)
224    }
225}
226
227#[derive(Debug, Clone)]
228pub struct AudioDeviceMock {
229    state: Arc<std::sync::Mutex<State>>,
230}
231
232impl AudioDeviceMock {
233    pub fn new() -> Self {
234        Self { state: Arc::new(std::sync::Mutex::new(State::new())) }
235    }
236
237    pub fn open(&self) -> Box<dyn AudioDevice> {
238        if self.with_state(State::mark_device_open) {
239            panic!("Mocked audio sink was already open for this mock");
240        }
241        Box::new(MockedAudioDevice::new(self.clone()))
242    }
243
244    pub fn open_sink(&self) -> Result<Box<dyn AudioSinkDevice>, OpenSinkError> {
245        self.with_state(State::open_sink)
246    }
247
248    pub fn register_sink(&self) -> AudioSinkDeviceMock {
249        self.with_state(State::register_sink)
250    }
251
252    pub fn register_open_sink_results(
253        &self,
254        results: impl IntoIterator<
255            Item = Result<Box<dyn AudioSinkDevice>, OpenSinkError>,
256        >,
257    ) {
258        self.with_state(|state| state.register_open_sink_results(results))
259    }
260
261    pub fn enable_open_sink_log(&self) {
262        self.with_state(State::enable_open_sink_log)
263    }
264
265    pub fn disable_open_sink_log(&self) {
266        self.with_state(State::disable_open_sink_log)
267    }
268
269    pub fn take_open_sink_log(&self) -> Option<u32> {
270        self.with_state(State::take_open_sink_log)
271    }
272
273    fn with_state<F, T>(&self, scope: F) -> T
274    where
275        F: FnOnce(&mut State) -> T,
276    {
277        let mut state = self.state.lock().expect("poisoned lock");
278        scope(&mut state)
279    }
280}
281
282#[derive(Debug, Clone)]
283pub struct AudioSinkDeviceMock {
284    state: Arc<std::sync::Mutex<SinkState>>,
285}
286
287impl AudioSinkDeviceMock {
288    pub fn new() -> Self {
289        Self { state: Arc::new(std::sync::Mutex::new(SinkState::new())) }
290    }
291
292    pub fn open(&self) -> Box<dyn AudioSinkDevice> {
293        if self.with_state(SinkState::mark_sink_open) {
294            panic!("Mocked audio sink was already open for this mock");
295        }
296        Box::new(MockedAudioSinkDevice::new(self.clone()))
297    }
298
299    pub fn enable_play_log(&self) {
300        self.with_state(SinkState::enable_play_log)
301    }
302
303    pub fn disable_play_log(&self) -> Option<Vec<Cow<'static, [u8]>>> {
304        self.with_state(SinkState::disable_play_log)
305    }
306
307    pub fn take_play_log(&self) -> Option<Vec<Cow<'static, [u8]>>> {
308        self.with_state(SinkState::take_play_log)
309    }
310
311    pub fn enable_set_volume_log(&self) {
312        self.with_state(SinkState::enable_set_volume_log)
313    }
314
315    pub fn disable_set_volume_log(&self) -> Option<Vec<f32>> {
316        self.with_state(SinkState::disable_set_volume_log)
317    }
318
319    pub fn take_set_volume_log(&self) -> Option<Vec<f32>> {
320        self.with_state(SinkState::take_set_volume_log)
321    }
322
323    pub fn force_pause(&self) {
324        self.with_state(SinkState::force_pause);
325    }
326
327    pub fn force_resume(&self) {
328        self.with_state(SinkState::force_resume);
329    }
330
331    pub fn is_playing(&self) -> Result<bool, CheckPlayStatusError> {
332        self.with_state(|state| state.is_playing())
333    }
334
335    pub fn register_play_results(
336        &self,
337        results: impl IntoIterator<Item = Result<(), PlayNowError>>,
338    ) {
339        self.with_state(|state| state.register_play_results(results))
340    }
341
342    pub fn register_set_volume_results(
343        &self,
344        results: impl IntoIterator<Item = Result<(), SetVolumeError>>,
345    ) {
346        self.with_state(|state| state.register_set_volume_results(results))
347    }
348
349    pub fn register_pause_results(
350        &self,
351        results: impl IntoIterator<Item = Result<(), PauseSinkError>>,
352    ) {
353        self.with_state(|state| state.register_pause_results(results))
354    }
355
356    pub fn register_resume_results(
357        &self,
358        results: impl IntoIterator<Item = Result<(), ResumeSinkError>>,
359    ) {
360        self.with_state(|state| state.register_resume_results(results))
361    }
362
363    pub fn register_clear_results(
364        &self,
365        results: impl IntoIterator<Item = Result<(), ClearSinkError>>,
366    ) {
367        self.with_state(|state| state.register_clear_results(results))
368    }
369
370    fn play_now(
371        &mut self,
372        bytes: Cow<'static, [u8]>,
373    ) -> Result<(), PlayNowError> {
374        self.with_state(|state| state.play_now(bytes))
375    }
376
377    fn set_volume(&mut self, volume: f32) -> Result<(), SetVolumeError> {
378        self.with_state(|state| state.set_volume(volume))
379    }
380
381    fn pause(&mut self) -> Result<(), PauseSinkError> {
382        self.with_state(SinkState::pause)
383    }
384
385    fn resume(&mut self) -> Result<(), ResumeSinkError> {
386        self.with_state(SinkState::resume)
387    }
388
389    fn clear(&mut self) -> Result<(), ClearSinkError> {
390        self.with_state(SinkState::clear)
391    }
392
393    fn with_state<F, T>(&self, scope: F) -> T
394    where
395        F: FnOnce(&mut SinkState) -> T,
396    {
397        let mut state = self.state.lock().expect("poisoned lock");
398        scope(&mut state)
399    }
400}
401
402#[derive(Debug)]
403struct MockedAudioDevice {
404    mock: AudioDeviceMock,
405}
406
407impl MockedAudioDevice {
408    pub fn new(mock: AudioDeviceMock) -> Self {
409        Self { mock }
410    }
411}
412
413impl AudioDevice for MockedAudioDevice {
414    fn open_sink(&mut self) -> Result<Box<dyn AudioSinkDevice>, OpenSinkError> {
415        self.mock.open_sink()
416    }
417}
418
419#[derive(Debug)]
420struct MockedAudioSinkDevice {
421    mock: AudioSinkDeviceMock,
422}
423
424impl MockedAudioSinkDevice {
425    pub fn new(mock: AudioSinkDeviceMock) -> Self {
426        Self { mock }
427    }
428}
429
430impl AudioSinkDevice for MockedAudioSinkDevice {
431    fn play_now(
432        &mut self,
433        bytes: Cow<'static, [u8]>,
434    ) -> Result<(), PlayNowError> {
435        self.mock.play_now(bytes)
436    }
437
438    fn set_volume(&mut self, volume: f32) -> Result<(), SetVolumeError> {
439        self.mock.set_volume(volume)
440    }
441
442    fn pause(&mut self) -> Result<(), PauseSinkError> {
443        self.mock.pause()
444    }
445
446    fn resume(&mut self) -> Result<(), ResumeSinkError> {
447        self.mock.resume()
448    }
449
450    fn clear(&mut self) -> Result<(), ClearSinkError> {
451        self.mock.clear()
452    }
453
454    fn is_playing(&self) -> Result<bool, CheckPlayStatusError> {
455        self.mock.is_playing()
456    }
457}