Krolyxon
Commit e7b881a

Branches

Refs →

budctlcratesbudctl-coresrctransportmock.rs

80 lines · 2.5 KB · Rust

1//! A scripted transport for tests: it checks every byte budctl sends and replays what the buds
2//! would answer, without hardware and without waiting for real time to pass.
3
4use std::collections::VecDeque;
5use std::sync::{Arc, Mutex};
6use std::time::Instant;
7
8use super::Transport;
9use crate::debug;
10use crate::error::{Error, Result};
11
12#[derive(Debug)]
13pub(crate) enum Step {
14 /// budctl must send exactly these bytes next.
15 Tx(Vec<u8>),
16 /// The buds send these bytes.
17 Rx(Vec<u8>),
18 /// The buds drop the link.
19 Close,
20}
21
22/// Cheap to clone: the test keeps one handle to check that the script was used up.
23#[derive(Clone, Default)]
24pub(crate) struct Script(Arc<Mutex<VecDeque<Step>>>);
25
26impl Script {
27 pub(crate) fn new(steps: Vec<Step>) -> Self {
28 Script(Arc::new(Mutex::new(steps.into())))
29 }
30
31 pub(crate) fn transport(&self) -> Box<dyn Transport> {
32 Box::new(self.clone())
33 }
34
35 pub(crate) fn assert_done(&self) {
36 let left = self.0.lock().unwrap();
37 assert!(left.is_empty(), "script not finished, next step: {:?}", left.front());
38 }
39}
40
41impl Transport for Script {
42 fn send(&mut self, bytes: &[u8]) -> Result<()> {
43 let mut steps = self.0.lock().unwrap();
44 match steps.pop_front() {
45 Some(Step::Tx(expected)) => assert_eq!(
46 debug::hex(bytes),
47 debug::hex(&expected),
48 "budctl sent something else than the script expects"
49 ),
50 other => panic!("unexpected send {} (next step: {other:?})", debug::hex(bytes)),
51 }
52 Ok(())
53 }
54
55 /// Returns the next scripted bytes from the buds. When the script expects budctl to send
56 /// next, the buds stay silent: the deadline "passes" at once.
57 fn recv(&mut self, _deadline: Instant) -> Result<Option<Vec<u8>>> {
58 let mut steps = self.0.lock().unwrap();
59 match steps.front() {
60 Some(Step::Rx(_)) => match steps.pop_front() {
61 Some(Step::Rx(bytes)) => Ok(Some(bytes)),
62 _ => unreachable!(),
63 },
64 Some(Step::Close) => {
65 steps.pop_front();
66 Err(Error::NotConnected(
67 "the buds closed the control link (script)".to_owned(),
68 ))
69 }
70 _ => Ok(None),
71 }
72 }
73}
74
75/// `"AA 07 00"` → `[0xAA, 0x07, 0x00]`
76pub(crate) fn hex(text: &str) -> Vec<u8> {
77 text.split_whitespace()
78 .map(|byte| u8::from_str_radix(byte, 16).unwrap())
79 .collect()
80}