Skip to content

Commit

Permalink
add SetDutyCycle mock
Browse files Browse the repository at this point in the history
this is the 1.0 equivalent of the old `PwmPin` trait (the mock for this
has been added in dbrgn#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 dbrgn#73
  • Loading branch information
rursprung authored and cdunster committed Sep 19, 2023
1 parent b17d3ed commit 389d77b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

- 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

Expand Down
1 change: 1 addition & 0 deletions src/eh1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
130 changes: 130 additions & 0 deletions src/eh1/pwm.rs
Original file line number Diff line number Diff line change
@@ -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<MockError>,
}

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<Transaction>;

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(())
}
}
}

0 comments on commit 389d77b

Please sign in to comment.