use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub(super) struct Invocation {
#[serde(default)]
pub(super) id: u64,
#[serde(default)]
pub(super) cmd: String,
pub(super) payload: serde_json::Value,
}
pub(super) fn parse_invocation(msg: &str) -> serde_json::Result<Invocation> {
serde_json::from_str(msg)
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
struct Payload {
armed: bool,
count: u8,
}
#[test]
fn parse_invocation_deserializes_typed_payload() {
let invocation = serde_json::from_str::<Invocation>(
r#"{"id":7,"cmd":"echo","payload":{"armed":true,"count":3}}"#,
)
.unwrap();
assert_eq!(invocation.id, 7);
assert_eq!(invocation.cmd, "echo");
assert_eq!(
serde_json::from_value::<Payload>(invocation.payload).unwrap(),
Payload {
armed: true,
count: 3
}
);
}
#[test]
fn parse_invocation_defaults_missing_metadata() {
let invocation = parse_invocation(r#"{"payload":null}"#).unwrap();
assert_eq!(invocation.id, 0);
assert_eq!(invocation.cmd, "");
assert_eq!(invocation.payload, serde_json::Value::Null);
}
#[test]
fn parse_invocation_rejects_invalid_json() {
assert!(parse_invocation("not json").is_err());
}
#[test]
fn invocation_serializes_typed_payload() {
let invocation = Invocation {
id: 9,
cmd: "status".into(),
payload: serde_json::json!({"armed": false, "count": 2}),
};
assert_eq!(
serde_json::to_string(&invocation).unwrap(),
r#"{"id":9,"cmd":"status","payload":{"armed":false,"count":2}}"#
);
}
}