From 69d3d8286f23e23484e404692aa7606c5b17e0c1 Mon Sep 17 00:00:00 2001 From: Ralph Ursprung Date: Sun, 2 Jul 2023 16:34:42 +0200 Subject: [PATCH] add `SetDutyCycle` mock this is the 1.0 equivalent of the old `PwmPin` trait (the mock for this has been added in #52). note that the test coverage is fully handled by the doc test which is why there's no additional `mod test` in this file. this fixes #73 --- CHANGELOG.md | 1 + src/eh1.rs | 1 + src/eh1/pin.rs | 6 +-- src/eh1/pwm.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 src/eh1/pwm.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a5eede..0386d02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## Unreleased ### Added +- Implement mock for `embedded_hal::pwm::SetDutyCycle` ### Fixed diff --git a/src/eh1.rs b/src/eh1.rs index 3f9918a..f179cb6 100644 --- a/src/eh1.rs +++ b/src/eh1.rs @@ -10,5 +10,6 @@ pub use crate::eh1::error::MockError; pub mod delay; pub mod i2c; pub mod pin; +pub mod pwm; pub mod serial; pub mod spi; diff --git a/src/eh1/pin.rs b/src/eh1/pin.rs index ce3ccb6..9f6741c 100644 --- a/src/eh1/pin.rs +++ b/src/eh1/pin.rs @@ -1,7 +1,7 @@ -//! Mock digital [`InputPin`] and [`OutputPin`] v2 implementations +//! Mock digital [`InputPin`] and [`OutputPin`] implementations //! -//! [`InputPin`]: https://docs.rs/embedded-hal/1.0.0-alpha.6/embedded_hal/digital/trait.InputPin.html -//! [`OutputPin`]: https://docs.rs/embedded-hal/1.0.0-alpha.6/embedded_hal/digital/trait.OutputPin.html +//! [`InputPin`]: https://docs.rs/embedded-hal/1.0.0-rc.1/embedded_hal/digital/trait.InputPin.html +//! [`OutputPin`]: https://docs.rs/embedded-hal/1.0.0-rc.1/embedded_hal/digital/trait.OutputPin.html //! //! ``` //! # use eh1 as embedded_hal; diff --git a/src/eh1/pwm.rs b/src/eh1/pwm.rs new file mode 100644 index 0000000..845ed38 --- /dev/null +++ b/src/eh1/pwm.rs @@ -0,0 +1,127 @@ +//! Mock implementations for +//! [`embedded_hal::pwm`](https://docs.rs/embedded-hal/1.0.0-rc.1/embedded_hal/pwm/index.html). +//! +//! Usage example: +//! ``` +//! use std::io::ErrorKind; +//! +//! # use eh1 as embedded_hal; +//! use embedded_hal::pwm::SetDutyCycle; +//! use embedded_hal_mock::eh1::{ +//! pwm::{Mock as PwmMock, Transaction as PwmTransaction}, +//! MockError, +//! }; +//! +//! // Configure expectations +//! let expectations = [ +//! PwmTransaction::get_max_duty_cycle(100), +//! PwmTransaction::set_duty_cycle(50), +//! PwmTransaction::set_duty_cycle(101).with_error(MockError::Io(ErrorKind::NotConnected)), +//! ]; +//! +//! // Create pin +//! let mut pwm = PwmMock::new(&expectations); +//! +//! // Run and test +//! pwm.set_duty_cycle_percent(50).unwrap(); +//! pwm.set_duty_cycle(101).expect_err("expected error return"); +//! +//! // Finalise expectations +//! pwm.done(); +//! ``` + +use eh1::pwm::{ErrorKind, ErrorType, SetDutyCycle}; + +use crate::{common::Generic, eh1::MockError}; + +/// MockPwm transaction +#[derive(PartialEq, Clone, Debug)] +pub struct Transaction { + /// Kind is the transaction kind (and data) expected + kind: TransactionKind, + /// Err is an optional error return for a transaction. + /// This is in addition to kind to allow validation that the transaction kind + /// is correct prior to returning the error. + err: Option, +} + +impl Transaction { + /// Create a new PWM transaction + pub fn new(kind: TransactionKind) -> Transaction { + Transaction { kind, err: None } + } + + /// Create a new [`TransactionKind::GetMaxDutyCycle`] transaction for [`SetDutyCycle::get_max_duty_cycle`]. + pub fn get_max_duty_cycle(duty: u16) -> Transaction { + Transaction::new(TransactionKind::GetMaxDutyCycle(duty)) + } + + /// Create a new [`TransactionKind::SetDutyCycle`] transaction for [`SetDutyCycle::set_duty_cycle`]. + pub fn set_duty_cycle(duty: u16) -> Transaction { + Transaction::new(TransactionKind::SetDutyCycle(duty)) + } + + /// Add an error return to a transaction + /// + /// This is used to mock failure behaviours. + pub fn with_error(mut self, error: MockError) -> Self { + self.err = Some(error); + self + } +} + +/// MockPwm transaction kind +#[derive(PartialEq, Clone, Debug)] +pub enum TransactionKind { + /// [`SetDutyCycle::get_max_duty_cycle`] which will return the defined duty. + GetMaxDutyCycle(u16), + /// [`SetDutyCycle::set_duty_cycle`] with the expected duty. + SetDutyCycle(u16), +} + +/// Mock PWM `SetDutyCycle` implementation +pub type Mock = Generic; + +impl eh1::pwm::Error for MockError { + fn kind(&self) -> ErrorKind { + ErrorKind::Other + } +} + +impl ErrorType for Mock { + type Error = MockError; +} + +impl SetDutyCycle for Mock { + fn get_max_duty_cycle(&self) -> u16 { + let mut s = self.clone(); + + let Transaction { kind, err } = s + .next() + .expect("no expectation for get_max_duty_cycle call"); + + assert_eq!(err, None, "error not supported by get_max_duty_cycle!"); + + match kind { + TransactionKind::GetMaxDutyCycle(duty) => duty, + other => panic!("expected get_max_duty_cycle, got {:?}", other), + } + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let Transaction { kind, err } = + self.next().expect("no expectation for set_duty_cycle call"); + + assert_eq!( + kind, + TransactionKind::SetDutyCycle(duty), + "expected set_duty_cycle" + ); + + if let Some(e) = err { + Err(e) + } else { + Ok(()) + } + } +}