From f5b3a2cc72459429cc428163ce8f8a541468875b 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 | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 src/eh1/pwm.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a5eede..abc860d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ contributions! - Support for both `embedded-hal` 0.x and 1.x in the same crate (#75) - Print a warning to stderr and fail test if a mock is dropped without having calling `.done()` on it, or if `.done()` is called twice (#59, #61) +- 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..39c4e80 --- /dev/null +++ b/src/eh1/pwm.rs @@ -0,0 +1,130 @@ +//! Mock implementations for [`embedded_hal::pwm`]. +//! +//! Usage example: +//! ``` +//! use std::io::ErrorKind; +//! +//! use embedded_hal_mock::eh1::MockError; +//! use embedded_hal_mock::eh1::pwm::{Transaction as PwmTransaction, Mock as PwmMock}; +//! use eh1::pwm::SetDutyCycle; +//! +//! let err = MockError::Io(ErrorKind::NotConnected); +//! +//! // Configure expectations +//! let expectations = [ +//! PwmTransaction::get_max_duty_cycle(100), +//! PwmTransaction::set_duty_cycle(50), +//! PwmTransaction::set_duty_cycle(101).with_error(err.clone()), +//! ]; +//! +//! // 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"); +//! +//! pwm.done(); +//! +//! // Update expectations +//! pwm.expect(&[]); +//! // ... +//! pwm.done(); +//! ``` + +use crate::common::Generic; +use crate::eh1::MockError; +use eh1::pwm::{ErrorKind, ErrorType, SetDutyCycle}; + +/// 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 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!"); + + if let TransactionKind::GetMaxDutyCycle(duty) = kind { + duty + } else { + unreachable!(); + } + } + + 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(()) + } + } +}