use crate::mqtt_serde::mqttv5::packet_id_ack::v5_packet_id_ack;
v5_packet_id_ack!(MqttPubComp, PUBCOMP, 0x00, "PUBCOMP", PubComp5, false);
#[cfg(test)]
mod tests {
use super::MqttPubComp;
use crate::mqtt_serde::control_packet::{MqttControlPacket, MqttPacket};
use crate::mqtt_serde::mqttv5::common::properties::Property;
use crate::mqtt_serde::parser::ParseOk;
#[test]
fn test_pubcomp_minimal_success() {
let pubcomp = MqttPubComp::new_success(0x1234);
let bytes = pubcomp.to_bytes().unwrap();
let expected = vec![0x70, 0x02, 0x12, 0x34];
assert_eq!(bytes, expected);
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(parsed_pubcomp), consumed) => {
assert_eq!(consumed, 4);
assert_eq!(parsed_pubcomp.packet_id, 0x1234);
assert_eq!(parsed_pubcomp.reason_code, 0x00);
assert!(parsed_pubcomp.properties.is_empty());
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_pubcomp_with_reason_code() {
let pubcomp = MqttPubComp::new(0x5678, 0x92, Vec::new()); let bytes = pubcomp.to_bytes().unwrap();
let expected = vec![0x70, 0x04, 0x56, 0x78, 0x92, 0x00];
assert_eq!(bytes, expected);
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(parsed_pubcomp), consumed) => {
assert_eq!(consumed, 6);
assert_eq!(parsed_pubcomp.packet_id, 0x5678);
assert_eq!(parsed_pubcomp.reason_code, 0x92);
assert!(parsed_pubcomp.properties.is_empty());
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_pubcomp_with_properties() {
let properties = vec![
Property::ReasonString("QoS 2 flow completed".to_string()),
Property::UserProperty("flow".to_string(), "qos2".to_string()),
];
let pubcomp = MqttPubComp::new(0xABCD, 0x00, properties); let bytes = pubcomp.to_bytes().unwrap();
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(parsed_pubcomp), _) => {
assert_eq!(parsed_pubcomp.packet_id, 0xABCD);
assert_eq!(parsed_pubcomp.reason_code, 0x00);
assert_eq!(parsed_pubcomp.properties.len(), 2);
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_pubcomp_parsing_minimal() {
let bytes = vec![0x70, 0x02, 0x00, 0x01];
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(pubcomp), consumed) => {
assert_eq!(consumed, 4);
assert_eq!(pubcomp.packet_id, 1);
assert_eq!(pubcomp.reason_code, 0x00); assert!(pubcomp.properties.is_empty());
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_pubcomp_error_conditions() {
let error_codes = vec![
0x80, 0x83, 0x92, ];
for &error_code in &error_codes {
let pubcomp = MqttPubComp::new_error(0x3000, error_code, Vec::new());
let bytes = pubcomp.to_bytes().unwrap();
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(parsed), _) => {
assert_eq!(parsed.packet_id, 0x3000);
assert_eq!(parsed.reason_code, error_code);
}
_ => panic!("Expected PUBCOMP packet for error code {:#x}", error_code),
}
}
}
#[test]
fn test_parse_pubcomp() {
let buffer: [u8; 6] = [0x70, 0x04, 0x00, 0x05, 0x00, 0x00];
let result = MqttPubComp::from_bytes(&buffer);
assert!(result.is_ok());
match result.unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(pubcomp), consumed) => {
assert_eq!(consumed, 6);
assert_eq!(pubcomp.packet_id, 5);
assert_eq!(pubcomp.reason_code, 0x00); assert!(pubcomp.properties.is_empty());
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_qos2_flow_completion() {
let packet_id = 0x1A2B;
let pubcomp_success = MqttPubComp::new_success(packet_id);
assert_eq!(pubcomp_success.packet_id, packet_id);
assert_eq!(pubcomp_success.reason_code, 0x00);
let pubcomp_error = MqttPubComp::new_error(
packet_id,
0x92, vec![Property::ReasonString("PUBREL not found".to_string())],
);
assert_eq!(pubcomp_error.packet_id, packet_id);
assert_eq!(pubcomp_error.reason_code, 0x92);
assert_eq!(pubcomp_error.properties.len(), 1);
}
#[test]
fn test_pubcomp_roundtrip_with_properties() {
let original_pubcomp = MqttPubComp::new(
0xDEAD,
0x83,
vec![
Property::ReasonString("Processing completed with warnings".to_string()),
Property::UserProperty("timestamp".to_string(), "2025-01-01T12:00:00Z".to_string()),
],
);
let bytes = original_pubcomp.to_bytes().unwrap();
match MqttPubComp::from_bytes(&bytes).unwrap() {
ParseOk::Packet(MqttPacket::PubComp5(parsed_pubcomp), _) => {
assert_eq!(parsed_pubcomp.packet_id, original_pubcomp.packet_id);
assert_eq!(parsed_pubcomp.reason_code, original_pubcomp.reason_code);
assert_eq!(
parsed_pubcomp.properties.len(),
original_pubcomp.properties.len()
);
}
_ => panic!("Expected PUBCOMP packet"),
}
}
#[test]
fn test_parse_pubcomp_2() {
let packet = vec![0x70, 0x03, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00];
let result = MqttPubComp::from_bytes(&packet);
match result {
Ok(ParseOk::Packet(MqttPacket::PubComp5(pubcomp), _consumed)) => {
assert_eq!(pubcomp.reason_code, 0);
assert_eq!(pubcomp.properties, vec![]);
}
_ => panic!("Invalid result: {:?}", result),
}
}
#[test]
fn test_parse_pubcomp_with_properties() {
let packet_bytes: [u8; 6] = [0x70, 0x04, 0x00, 0x02, 0x00, 0x00];
let result = MqttPubComp::from_bytes(&packet_bytes);
match result {
Ok(ParseOk::Packet(MqttPacket::PubComp5(pubcomp), _consumed)) => {
assert_eq!(pubcomp.packet_id, 2);
assert_eq!(pubcomp.reason_code, 0);
assert_eq!(pubcomp.properties, vec![]);
}
_ => panic!("Invalid result: {:?}", result),
}
}
}