pub mod error;
pub mod message;
pub mod stream;
pub mod tungstenite;
#[cfg(feature = "transport-sockudo")]
pub mod sockudo;
pub use error::TransportError;
pub use message::{CloseFrame, Message};
pub use stream::{BoxedWsTransport, WsTransport};
#[cfg(test)]
mod tests {
use bytes::Bytes;
use proptest::prelude::*;
use rstest::rstest;
#[cfg(feature = "transport-sockudo")]
use sockudo_ws::protocol::Message as SockudoMessage;
use tokio_tungstenite::tungstenite::Message as TungsteniteMessage;
use super::*;
fn message_strategy() -> impl Strategy<Value = Message> {
prop_oneof![
any::<String>().prop_map(Message::text),
prop::collection::vec(any::<u8>(), 0..256).prop_map(Message::binary),
prop::collection::vec(any::<u8>(), 0..=125)
.prop_map(|bytes| Message::ping(Bytes::from(bytes))),
prop::collection::vec(any::<u8>(), 0..=125)
.prop_map(|bytes| Message::pong(Bytes::from(bytes))),
prop::option::of((any::<u16>(), any::<String>())).prop_map(|frame| {
Message::Close(frame.map(|(code, reason)| CloseFrame::new(code, reason)))
}),
]
}
proptest! {
#[rstest]
fn message_conversions_round_trip(message in message_strategy()) {
let tungstenite = TungsteniteMessage::try_from(message.clone()).unwrap();
let tungstenite_round_trip = Message::from(tungstenite);
prop_assert_eq!(&tungstenite_round_trip, &message);
#[cfg(feature = "transport-sockudo")]
{
let sockudo = SockudoMessage::from(message.clone());
prop_assert_eq!(Message::from(sockudo), message);
}
}
#[rstest]
fn invalid_text_conversion_is_backend_specific(
bytes in prop::collection::vec(any::<u8>(), 1..256)
.prop_filter("invalid UTF-8", |bytes| std::str::from_utf8(bytes).is_err())
) {
let message = Message::Text(Bytes::from(bytes));
let tungstenite = TungsteniteMessage::try_from(message.clone());
prop_assert!(matches!(tungstenite, Err(TransportError::InvalidUtf8)));
#[cfg(feature = "transport-sockudo")]
{
let sockudo = SockudoMessage::from(message.clone());
prop_assert_eq!(Message::from(sockudo), message);
}
}
}
}