use eh0 as embedded_hal;
use embedded_hal::{
digital::v2::{InputPin, OutputPin, ToggleableOutputPin},
PwmPin,
};
use super::error::MockError;
use crate::common::Generic;
pub type PwmDuty = u16;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Transaction {
kind: TransactionKind,
err: Option<MockError>,
}
#[derive(PartialEq, Eq, Copy, 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 toggle() -> Transaction {
Transaction::new(TransactionKind::Toggle)
}
pub fn set(state: State) -> Transaction {
Transaction::new(TransactionKind::Set(state))
}
pub fn disable() -> Transaction {
Transaction::new(TransactionKind::Disable)
}
pub fn enable() -> Transaction {
Transaction::new(TransactionKind::Enable)
}
pub fn get_duty(duty: PwmDuty) -> Transaction {
Transaction::new(TransactionKind::GetDuty(duty))
}
pub fn get_max_duty(max_duty: PwmDuty) -> Transaction {
Transaction::new(TransactionKind::GetMaxDuty(max_duty))
}
pub fn set_duty(expected_duty: PwmDuty) -> Transaction {
Transaction::new(TransactionKind::SetDuty(expected_duty))
}
pub fn with_error(mut self, error: MockError) -> Self {
assert!(
self.kind.supports_errors(),
"the transaction kind supports errors"
);
self.err = Some(error);
self
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum TransactionKind {
Set(State),
Get(State),
Toggle,
Disable,
Enable,
GetDuty(PwmDuty),
GetMaxDuty(PwmDuty),
SetDuty(PwmDuty),
}
impl TransactionKind {
fn is_get(&self) -> bool {
match self {
TransactionKind::Get(_) => true,
_ => false,
}
}
fn supports_errors(&self) -> bool {
match self {
TransactionKind::Set(_) | TransactionKind::Get(_) | TransactionKind::Toggle => 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),
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),
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!(kind.is_get(), "expected pin::get");
if let Some(e) = err {
Err(e)
} 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!(kind.is_get(), "expected pin::get");
if let Some(e) = err {
Err(e)
} else if let TransactionKind::Get(v) = kind {
Ok(v == State::Low)
} else {
unreachable!();
}
}
}
impl ToggleableOutputPin for Mock {
type Error = MockError;
fn toggle(&mut self) -> Result<(), Self::Error> {
let Transaction { kind, err } = self.next().expect("no expectation for pin::toggle call");
assert_eq!(kind, TransactionKind::Toggle, "expected pin::toggle");
match err {
Some(e) => Err(e),
None => Ok(()),
}
}
}
impl PwmPin for Mock {
type Duty = PwmDuty;
fn disable(&mut self) {
let Transaction { kind, .. } = self.next().expect("no expectation for pin::disable call");
assert_eq!(kind, TransactionKind::Disable, "expected pin::disable");
}
fn enable(&mut self) {
let Transaction { kind, .. } = self.next().expect("no expectation for pin::enable call");
assert_eq!(kind, TransactionKind::Enable, "expected pin::enable");
}
fn get_duty(&self) -> Self::Duty {
let mut s = self.clone();
let Transaction { kind, .. } = s.next().expect("no expectation for pin::get_duty call");
if let TransactionKind::GetDuty(duty) = kind {
duty
} else {
panic!("expected pin::get_duty");
}
}
fn get_max_duty(&self) -> Self::Duty {
let mut s = self.clone();
let Transaction { kind, .. } = s.next().expect("no expectation for pin::get_max_duty call");
if let TransactionKind::GetMaxDuty(max_duty) = kind {
max_duty
} else {
panic!("expected pin::get_max_duty");
}
}
fn set_duty(&mut self, duty: Self::Duty) {
let Transaction { kind, .. } = self.next().expect("no expectation for pin::set_duty call");
assert_eq!(
kind,
TransactionKind::SetDuty(duty),
"expected pin::set_duty"
);
}
}
#[cfg(test)]
mod test {
use std::io::ErrorKind;
use eh0 as embedded_hal;
use embedded_hal::{
digital::v2::{InputPin, OutputPin},
PwmPin,
};
use super::{super::error::MockError, TransactionKind::*, *};
#[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();
}
#[test]
fn test_toggleable_output_pin() {
let expectations = [
Transaction::new(Toggle),
Transaction::toggle(),
Transaction::new(Toggle).with_error(MockError::Io(ErrorKind::NotConnected)),
];
let mut pin = Mock::new(&expectations);
pin.toggle().unwrap();
pin.toggle().unwrap();
pin.toggle().expect_err("expected error return");
pin.done();
}
#[test]
fn test_pwm_pin() {
let expected_duty = 10_000;
let expectations = [
Transaction::new(Enable),
Transaction::new(GetMaxDuty(expected_duty)),
Transaction::new(SetDuty(expected_duty)),
Transaction::new(GetDuty(expected_duty)),
Transaction::new(Disable),
];
let mut pin = Mock::new(&expectations);
pin.enable();
let max_duty = pin.get_max_duty();
pin.set_duty(max_duty);
assert_eq!(pin.get_duty(), expected_duty);
pin.disable();
pin.done();
}
}