use crate::common::Generic;
use crate::error::MockError;
use embedded_hal::digital::v2::{InputPin, OutputPin};
#[derive(PartialEq, Clone, Debug)]
pub struct Transaction {
kind: TransactionKind,
err: Option<MockError>,
}
#[derive(PartialEq, Clone, Debug)]
pub enum State {
Low,
High,
}
impl Transaction {
pub fn new(kind: TransactionKind) -> Transaction {
Transaction { kind, err: None }
}
pub fn get(state: State) -> Transaction {
Transaction::new(TransactionKind::Get(state))
}
pub fn set(state: State) -> Transaction {
Transaction::new(TransactionKind::Set(state))
}
pub fn with_error(mut self, error: MockError) -> Self {
self.err = Some(error);
self
}
}
#[derive(PartialEq, Clone, Debug)]
pub enum TransactionKind {
Set(State),
Get(State),
}
impl TransactionKind {
fn is_get(&self) -> bool {
match self {
TransactionKind::Get(_) => true,
_ => false,
}
}
}
pub type Mock = Generic<Transaction>;
impl OutputPin for Mock {
type Error = MockError;
fn set_low(&mut self) -> Result<(), Self::Error> {
let Transaction { kind, err } = self.next().expect("no expectation for pin::set_low call");
assert_eq!(
kind,
TransactionKind::Set(State::Low),
"expected pin::set_low"
);
match err {
Some(e) => Err(e.clone()),
None => Ok(()),
}
}
fn set_high(&mut self) -> Result<(), Self::Error> {
let Transaction { kind, err } = self.next().expect("no expectation for pin::set_high call");
assert_eq!(
kind,
TransactionKind::Set(State::High),
"expected pin::set_high"
);
match err {
Some(e) => Err(e.clone()),
None => Ok(()),
}
}
}
impl InputPin for Mock {
type Error = MockError;
fn is_high(&self) -> Result<bool, Self::Error> {
let mut s = self.clone();
let Transaction { kind, err } = s.next().expect("no expectation for pin::is_high call");
assert_eq!(kind.is_get(), true, "expected pin::get");
if let Some(e) = err {
Err(e.clone())
} else if let TransactionKind::Get(v) = kind {
Ok(v == State::High)
} else {
unreachable!();
}
}
fn is_low(&self) -> Result<bool, Self::Error> {
let mut s = self.clone();
let Transaction { kind, err } = s.next().expect("no expectation for pin::is_low call");
assert_eq!(kind.is_get(), true, "expected pin::get");
if let Some(e) = err {
Err(e.clone())
} else if let TransactionKind::Get(v) = kind {
Ok(v == State::Low)
} else {
unreachable!();
}
}
}
#[cfg(test)]
mod test {
use std::io::ErrorKind;
use crate::error::MockError;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use crate::pin::TransactionKind::{Get, Set};
use crate::pin::{Mock, State, Transaction};
#[test]
fn test_input_pin() {
let expectations = [
Transaction::new(Get(State::High)),
Transaction::new(Get(State::High)),
Transaction::new(Get(State::Low)),
Transaction::new(Get(State::Low)),
Transaction::new(Get(State::High)).with_error(MockError::Io(ErrorKind::NotConnected)),
];
let mut pin = Mock::new(&expectations);
assert_eq!(pin.is_high().unwrap(), true);
assert_eq!(pin.is_low().unwrap(), false);
assert_eq!(pin.is_high().unwrap(), false);
assert_eq!(pin.is_low().unwrap(), true);
pin.is_low().expect_err("expected error return");
pin.done();
}
#[test]
fn test_output_pin() {
let expectations = [
Transaction::new(Set(State::High)),
Transaction::new(Set(State::Low)),
Transaction::new(Set(State::High)).with_error(MockError::Io(ErrorKind::NotConnected)),
];
let mut pin = Mock::new(&expectations);
pin.set_high().unwrap();
pin.set_low().unwrap();
pin.set_high().expect_err("expected error return");
pin.done();
}
}