use std::collections::VecDeque;
use crate::{ReaderTransport, frame::protocol_crc16};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MockInteraction {
pub request_command: u8,
pub response_status: u16,
pub response_data: Vec<u8>,
}
#[derive(Debug, Default)]
pub struct MockTransport {
rx: VecDeque<u8>,
scripted: VecDeque<MockInteraction>,
}
impl MockTransport {
pub fn scripted(interactions: Vec<MockInteraction>) -> Self {
Self {
rx: VecDeque::new(),
scripted: interactions.into(),
}
}
pub fn from_replies(replies: Vec<Vec<u8>>) -> Self {
let mut rx = VecDeque::new();
for reply in replies {
rx.extend(reply);
}
Self {
rx,
scripted: VecDeque::new(),
}
}
}
impl ReaderTransport for MockTransport {
type Error = &'static str;
async fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> {
if let Some(next) = self.scripted.pop_front() {
if data.len() < 3 || data[0] != 0xFF {
return Err("invalid request frame");
}
if data[2] != next.request_command {
return Err("unexpected request command");
}
let reply = reply_frame(
next.request_command,
next.response_status,
&next.response_data,
);
self.rx.extend(reply);
}
Ok(())
}
async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
if self.rx.len() < buf.len() {
return Err("eof");
}
for b in buf.iter_mut() {
*b = self.rx.pop_front().ok_or("eof")?;
}
Ok(())
}
}
pub fn reply_frame(command: u8, status: u16, data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(1 + 1 + 1 + 2 + data.len() + 2);
out.push(0xFF);
out.push(data.len() as u8);
out.push(command);
out.extend_from_slice(&status.to_be_bytes());
out.extend_from_slice(data);
let crc = protocol_crc16(&out);
out.extend_from_slice(&crc.to_be_bytes());
out
}