use super::{Frame, FrameType, validate_stream};
use crate::protocol::{CausalContext, MessageEnvelope, ProtocolError, SchemaId};
#[test]
fn frame_type_discriminants_round_trip() {
let values = [
(0x01, FrameType::Connect),
(0x02, FrameType::ConnectAck),
(0x03, FrameType::ConnectError),
(0x04, FrameType::Disconnect),
(0x05, FrameType::Subscribe),
(0x06, FrameType::SubscribeAck),
(0x07, FrameType::SubscribeError),
(0x08, FrameType::Unsubscribe),
(0x09, FrameType::Publish),
(0x0A, FrameType::PublishAck),
(0x0B, FrameType::PublishError),
(0x0C, FrameType::ConversationOpen),
(0x0D, FrameType::ConversationMessage),
(0x0E, FrameType::ConversationClose),
(0x0F, FrameType::ConversationError),
(0x10, FrameType::Accept),
(0x11, FrameType::Defer),
(0x12, FrameType::Reject),
(0x13, FrameType::Ping),
(0x14, FrameType::Pong),
(0x15, FrameType::Push),
(0x16, FrameType::PushReply),
(0x17, FrameType::WorkerRegister),
(0x18, FrameType::WorkerRegisterAck),
(0x19, FrameType::Deliver),
(0x1D, FrameType::LinkOpen),
(0x1E, FrameType::LinkOpenAck),
(0x1F, FrameType::LinkMessage),
(0x20, FrameType::DisconnectReason),
];
for (wire, frame_type) in values {
assert_eq!(FrameType::from(wire), frame_type);
assert_eq!(u8::from(frame_type), wire);
}
assert_eq!(FrameType::from(0x1A), FrameType::Unknown(0x1A));
for (wire, _) in values {
assert_ne!(wire, 0x1A);
}
assert_eq!(FrameType::from(0x80), FrameType::Unknown(0x80));
assert_eq!(u8::from(FrameType::Unknown(0x80)), 0x80);
}
#[test]
fn constructors_validate_streams() {
assert!(Frame::new_ping(0).is_ok());
assert!(matches!(
Frame::new_ping(1),
Err(ProtocolError::InvalidStream { .. })
));
let envelope = sample_envelope();
assert!(Frame::new_publish(1, "orders", envelope.clone()).is_ok());
assert!(matches!(
Frame::new_publish(0, "orders", envelope),
Err(ProtocolError::InvalidStream { .. })
));
assert!(validate_stream(FrameType::Accept, 2).is_ok());
let deliver_envelope = sample_envelope();
assert!(Frame::new_deliver(1, 1, deliver_envelope.clone()).is_ok());
assert!(matches!(
Frame::new_deliver(0, 1, deliver_envelope),
Err(ProtocolError::InvalidStream { .. })
));
}
fn sample_envelope() -> MessageEnvelope {
MessageEnvelope::new(
SchemaId::new([0x55; 32]),
CausalContext::independent(),
vec![1, 2, 3],
)
}
#[test]
fn a_connect_debug_names_its_token_by_length_only() {
let frame = Frame::Connect {
flags: 0,
min_version: crate::protocol::ProtocolVersion::new(1, 0),
max_version: crate::protocol::ProtocolVersion::new(1, 0),
auth_token: vec![200, 201, 202, 203],
};
let rendered = format!("{frame:?}");
for shown in ["200, 201", "c8c9"] {
assert!(
!rendered.contains(shown),
"the Debug of Frame::Connect shows its token as {shown:?}: {rendered}"
);
}
assert!(
rendered.contains("auth_token: 4 bytes"),
"the Debug of Frame::Connect must name its token by length: {rendered}"
);
}
#[test]
fn every_other_frame_keeps_the_derived_debug() {
assert_eq!(
format!("{:?}", Frame::Ping { flags: 3 }),
"Ping { flags: 3 }"
);
assert_eq!(
format!(
"{:?}",
Frame::PublishError {
flags: 0,
stream_id: 9,
reason_code: 4,
message: Some("full".to_owned()),
}
),
"PublishError { flags: 0, stream_id: 9, reason_code: 4, message: Some(\"full\") }"
);
assert_eq!(
format!(
"{:#?}",
Frame::Unsubscribe {
flags: 1,
stream_id: 2,
subscription_id: 3,
}
),
"Unsubscribe {\n flags: 1,\n stream_id: 2,\n subscription_id: 3,\n}"
);
}