use crate::Error;
use serde::{Serialize, Serializer};
#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(
feature = "python",
pyo3::prelude::pyclass(from_py_object, get_all, eq, eq_int)
)]
pub enum AlarmVolume {
#[default]
Default,
Mute,
Low,
Normal,
High,
}
impl AlarmVolume {
fn is_default(&self) -> bool {
matches!(self, Self::Default)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Default, Serialize)]
#[cfg_attr(
feature = "python",
pyo3::prelude::pyclass(from_py_object, get_all, eq, eq_int)
)]
pub enum AlarmRingtone {
#[default]
Default,
#[serde(rename = "Alarm 1")]
Alarm1,
#[serde(rename = "Alarm 2")]
Alarm2,
#[serde(rename = "Alarm 3")]
Alarm3,
#[serde(rename = "Alarm 4")]
Alarm4,
#[serde(rename = "Alarm 5")]
Alarm5,
#[serde(rename = "Connection 1")]
Connection1,
#[serde(rename = "Connection 2")]
Connection2,
#[serde(rename = "Doorbell Ring 1")]
DoorbellRing1,
#[serde(rename = "Doorbell Ring 2")]
DoorbellRing2,
#[serde(rename = "Doorbell Ring 3")]
DoorbellRing3,
#[serde(rename = "Doorbell Ring 4")]
DoorbellRing4,
#[serde(rename = "Doorbell Ring 5")]
DoorbellRing5,
#[serde(rename = "Doorbell Ring 6")]
DoorbellRing6,
#[serde(rename = "Doorbell Ring 7")]
DoorbellRing7,
#[serde(rename = "Doorbell Ring 8")]
DoorbellRing8,
#[serde(rename = "Doorbell Ring 9")]
DoorbellRing9,
#[serde(rename = "Doorbell Ring 10")]
DoorbellRing10,
#[serde(rename = "Dripping Tap")]
DrippingTap,
#[serde(rename = "Phone Ring")]
PhoneRing,
}
impl AlarmRingtone {
fn is_default(&self) -> bool {
matches!(self, Self::Default)
}
}
#[derive(Debug, Clone, Copy)]
pub enum AlarmDuration {
Continuous,
Once,
Seconds(u32),
}
impl AlarmDuration {
fn is_continuous(&self) -> bool {
matches!(self, Self::Continuous)
}
}
impl Serialize for AlarmDuration {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let as_option = match self {
Self::Continuous => None,
Self::Once => Some(0),
Self::Seconds(seconds) => Some(*seconds),
};
Serialize::serialize(&as_option, serializer)
}
}
#[derive(Debug, Serialize)]
pub(crate) struct PlayAlarmParams {
#[serde(skip_serializing_if = "AlarmRingtone::is_default")]
alarm_type: AlarmRingtone,
#[serde(skip_serializing_if = "AlarmVolume::is_default")]
alarm_volume: AlarmVolume,
#[serde(skip_serializing_if = "AlarmDuration::is_continuous")]
alarm_duration: AlarmDuration,
}
impl PlayAlarmParams {
pub(crate) fn new(
ringtone: AlarmRingtone,
volume: AlarmVolume,
duration: AlarmDuration,
) -> Result<Self, Error> {
let params = Self {
alarm_type: ringtone,
alarm_volume: volume,
alarm_duration: duration,
};
params.validate()?;
Ok(params)
}
fn validate(&self) -> Result<(), Error> {
match self.alarm_duration {
AlarmDuration::Seconds(0) => Err(Error::Validation {
field: "duration".to_string(),
message: "The seconds value must be greater than zero".to_string(),
}),
_ => Ok(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_inputs() {
for valid_ringtone in [AlarmRingtone::Default, AlarmRingtone::Alarm1] {
for valid_volume in [AlarmVolume::Default, AlarmVolume::Normal] {
for valid_duration in [
AlarmDuration::Continuous,
AlarmDuration::Once,
AlarmDuration::Seconds(1),
] {
let result = PlayAlarmParams::new(valid_ringtone, valid_volume, valid_duration);
assert!(result.is_ok());
}
}
}
}
#[test]
fn test_invalid_inputs() {
let result = PlayAlarmParams::new(
AlarmRingtone::Default,
AlarmVolume::Default,
AlarmDuration::Seconds(0),
);
assert!(matches!(
result.err(),
Some(Error::Validation { field, message }) if field == "duration" && message == "The seconds value must be greater than zero"
));
}
fn params_to_json(
ringtone: AlarmRingtone,
volume: AlarmVolume,
duration: AlarmDuration,
) -> String {
let params = PlayAlarmParams::new(ringtone, volume, duration).unwrap();
serde_json::to_string(¶ms).expect("Serialization failed")
}
#[test]
fn test_serialize_params_where_ringtone_is_some() {
assert_eq!(
r#"{"alarm_type":"Alarm 1"}"#,
params_to_json(
AlarmRingtone::Alarm1,
AlarmVolume::Default,
AlarmDuration::Continuous
)
);
}
#[test]
fn test_serialize_params_where_volume_is_some() {
assert_eq!(
r#"{"alarm_volume":"mute"}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Mute,
AlarmDuration::Continuous
)
);
assert_eq!(
r#"{"alarm_volume":"low"}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Low,
AlarmDuration::Continuous
)
);
assert_eq!(
r#"{"alarm_volume":"normal"}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Normal,
AlarmDuration::Continuous
)
);
assert_eq!(
r#"{"alarm_volume":"high"}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::High,
AlarmDuration::Continuous
)
);
}
#[test]
fn test_serialize_params_where_duration_is_continuous() {
assert_eq!(
r#"{}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Default,
AlarmDuration::Continuous
)
);
}
#[test]
fn test_serialize_params_where_duration_is_once() {
assert_eq!(
r#"{"alarm_duration":0}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Default,
AlarmDuration::Once
)
);
}
#[test]
fn test_serialize_params_where_duration_is_1second() {
assert_eq!(
r#"{"alarm_duration":1}"#,
params_to_json(
AlarmRingtone::Default,
AlarmVolume::Default,
AlarmDuration::Seconds(1)
)
);
}
#[test]
fn test_serialize_all_params_are_some_and_duration_is_1second() {
assert_eq!(
r#"{"alarm_type":"Doorbell Ring 1","alarm_volume":"normal","alarm_duration":1}"#,
params_to_json(
AlarmRingtone::DoorbellRing1,
AlarmVolume::Normal,
AlarmDuration::Seconds(1)
)
);
}
}