use serde::{Deserialize, Serialize};
pub const SUBSCRIBE: &str = "button.subscribe";
pub const DELIVER: &str = "button.deliver";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ButtonPress {
pub pin: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
pub kind: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub action: Option<String>,
#[serde(default)]
pub timestamp_ms: u64,
}
impl ButtonPress {
pub fn is_long(&self) -> bool {
self.kind == "long"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_unmapped_button_round_trips_without_an_action_field() {
let press = ButtonPress {
pin: 5,
label: None,
kind: "short".to_string(),
action: None,
timestamp_ms: 12,
};
let json = serde_json::to_string(&press).unwrap();
assert!(
!json.contains("action"),
"an absent action is omitted, not sent as null: {json}"
);
assert_eq!(serde_json::from_str::<ButtonPress>(&json).unwrap(), press);
}
#[test]
fn a_mapped_button_round_trips_with_its_action() {
let press = ButtonPress {
pin: 13,
label: Some("B3".to_string()),
kind: "long".to_string(),
action: Some("pair_drone".to_string()),
timestamp_ms: 4242,
};
let json = serde_json::to_string(&press).unwrap();
assert_eq!(serde_json::from_str::<ButtonPress>(&json).unwrap(), press);
assert!(press.is_long());
}
#[test]
fn an_explicit_null_action_decodes_as_unmapped() {
let press: ButtonPress =
serde_json::from_str(r#"{"pin":6,"kind":"short","action":null,"timestamp_ms":1}"#)
.unwrap();
assert_eq!(press.action, None);
assert!(!press.is_long());
}
#[test]
fn a_missing_timestamp_defaults_rather_than_failing_the_decode() {
let press: ButtonPress = serde_json::from_str(r#"{"pin":19,"kind":"short"}"#).unwrap();
assert_eq!(press.timestamp_ms, 0);
}
}