use crate::error::{MmError, MmResult};
use std::collections::VecDeque;
pub trait Transport: Send {
fn send(&mut self, cmd: &str) -> MmResult<()>;
fn receive_line(&mut self) -> MmResult<String>;
fn purge(&mut self) -> MmResult<()>;
fn send_recv(&mut self, cmd: &str) -> MmResult<String> {
self.send(cmd)?;
self.receive_line()
}
fn send_bytes(&mut self, bytes: &[u8]) -> MmResult<()> {
let s: String = bytes.iter().map(|&b| b as char).collect();
self.send(&s)
}
fn receive_bytes(&mut self, n: usize) -> MmResult<Vec<u8>> {
let line = self.receive_line()?;
let bytes: Vec<u8> = line.bytes().collect();
Ok(bytes[..bytes.len().min(n)].to_vec())
}
}
pub struct MockTransport {
script: VecDeque<(Option<String>, String)>,
bytes_script: VecDeque<Vec<u8>>,
pub received: Vec<String>,
pub received_bytes: Vec<Vec<u8>>,
}
impl MockTransport {
pub fn new() -> Self {
Self {
script: VecDeque::new(),
bytes_script: VecDeque::new(),
received: Vec::new(),
received_bytes: Vec::new(),
}
}
pub fn expect(mut self, cmd: &str, response: &str) -> Self {
self.script.push_back((Some(cmd.to_string()), response.to_string()));
self
}
pub fn any(mut self, response: &str) -> Self {
self.script.push_back((None, response.to_string()));
self
}
pub fn drain_any(mut self, responses: impl IntoIterator<Item = &'static str>) -> Self {
for r in responses {
self.script.push_back((None, r.to_string()));
}
self
}
pub fn expect_binary(mut self, response: &[u8]) -> Self {
self.bytes_script.push_back(response.to_vec());
self
}
}
impl Default for MockTransport {
fn default() -> Self {
Self::new()
}
}
impl Transport for MockTransport {
fn send(&mut self, cmd: &str) -> MmResult<()> {
self.received.push(cmd.to_string());
Ok(())
}
fn receive_line(&mut self) -> MmResult<String> {
match self.script.pop_front() {
Some((expected, response)) => {
if let Some(exp) = expected {
let sent = self.received.last().cloned().unwrap_or_default();
if sent != exp {
return Err(MmError::LocallyDefined(format!(
"MockTransport: expected command {:?}, got {:?}",
exp, sent
)));
}
}
Ok(response)
}
None => Err(MmError::SerialTimeout),
}
}
fn purge(&mut self) -> MmResult<()> {
Ok(())
}
fn send_bytes(&mut self, bytes: &[u8]) -> MmResult<()> {
self.received_bytes.push(bytes.to_vec());
Ok(())
}
fn receive_bytes(&mut self, n: usize) -> MmResult<Vec<u8>> {
match self.bytes_script.pop_front() {
Some(data) => Ok(data[..data.len().min(n)].to_vec()),
None => Err(MmError::SerialTimeout),
}
}
}