132 lines
4.7 KiB
Rust
132 lines
4.7 KiB
Rust
// file: crates/common/game-realtime-transport-lib/unit_tests/contract.rs
|
|
// version: 1
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
struct TestSender {
|
|
closed: bool,
|
|
sent_bytes: usize,
|
|
}
|
|
|
|
impl crate::RealtimeSender for TestSender {
|
|
type SendFuture<'a>
|
|
= std::future::Ready<Result<(), crate::TransportError>>
|
|
where
|
|
Self: 'a;
|
|
type CloseFuture<'a>
|
|
= std::future::Ready<Result<(), crate::TransportError>>
|
|
where
|
|
Self: 'a;
|
|
|
|
fn send(&mut self, message: crate::TransportMessage) -> Self::SendFuture<'_> {
|
|
self.sent_bytes = self.sent_bytes.saturating_add(message.len());
|
|
return std::future::ready(Ok(()));
|
|
}
|
|
|
|
fn close(&mut self) -> Self::CloseFuture<'_> {
|
|
self.closed = true;
|
|
return std::future::ready(Ok(()));
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
struct TestReceiver;
|
|
|
|
impl crate::RealtimeReceiver for TestReceiver {
|
|
type ReceiveFuture<'a>
|
|
= std::future::Ready<Result<crate::TransportReceive, crate::TransportError>>
|
|
where
|
|
Self: 'a;
|
|
|
|
fn receive(&mut self) -> Self::ReceiveFuture<'_> {
|
|
return std::future::ready(Ok(crate::TransportReceive::Closed));
|
|
}
|
|
}
|
|
|
|
struct TestConnection;
|
|
|
|
impl crate::RealtimeConnection for TestConnection {
|
|
type Sender = TestSender;
|
|
type Receiver = TestReceiver;
|
|
|
|
fn split(self) -> (Self::Sender, Self::Receiver) {
|
|
return (TestSender { closed: false, sent_bytes: 0 }, TestReceiver);
|
|
}
|
|
}
|
|
|
|
fn poll_ready<T>(future: impl core::future::Future<Output = T>) -> T {
|
|
let mut future = std::pin::pin!(future);
|
|
let waker = std::task::Waker::noop();
|
|
let mut context = std::task::Context::from_waker(waker);
|
|
return match core::future::Future::poll(future.as_mut(), &mut context) {
|
|
std::task::Poll::Ready(value) => value,
|
|
std::task::Poll::Pending => unreachable!("test future unexpectedly remained pending"),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn message_preserves_owned_binary_payload() {
|
|
let message = crate::TransportMessage::new(vec![0, 1, 2, 255]);
|
|
assert_eq!(message.as_bytes(), &[0, 1, 2, 255]);
|
|
assert_eq!(message.len(), 4);
|
|
assert!(!message.is_empty());
|
|
assert_eq!(message.into_bytes(), vec![0, 1, 2, 255]);
|
|
}
|
|
|
|
#[test]
|
|
fn empty_message_remains_a_valid_transport_payload() {
|
|
let message = crate::TransportMessage::new(Vec::new());
|
|
assert!(message.is_empty());
|
|
assert_eq!(message.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn clean_remote_close_is_distinct_from_transport_error() {
|
|
let mut receiver = TestReceiver;
|
|
let received = poll_ready(crate::RealtimeReceiver::receive(&mut receiver));
|
|
assert_eq!(received, Ok(crate::TransportReceive::Closed));
|
|
}
|
|
|
|
#[test]
|
|
fn connection_split_produces_independent_contract_halves() {
|
|
let (mut sender, mut receiver) = crate::RealtimeConnection::split(TestConnection);
|
|
assert_eq!(poll_ready(crate::RealtimeSender::send(&mut sender, crate::TransportMessage::new(vec![1, 2, 3]))), Ok(()));
|
|
assert_eq!(sender.sent_bytes, 3);
|
|
assert_eq!(poll_ready(crate::RealtimeReceiver::receive(&mut receiver)), Ok(crate::TransportReceive::Closed));
|
|
assert_eq!(poll_ready(crate::RealtimeSender::close(&mut sender)), Ok(()));
|
|
assert!(sender.closed);
|
|
}
|
|
|
|
#[test]
|
|
fn message_receive_variant_preserves_payload() {
|
|
let received = crate::TransportReceive::Message(crate::TransportMessage::new(vec![4, 5, 6]));
|
|
assert_eq!(received, crate::TransportReceive::Message(crate::TransportMessage::new(vec![4, 5, 6])));
|
|
}
|
|
|
|
#[test]
|
|
fn transport_error_preserves_stable_kind_and_diagnostic_detail() {
|
|
let error = crate::TransportError::new(crate::TransportErrorKind::Timeout, "send deadline exceeded");
|
|
assert_eq!(error.kind(), crate::TransportErrorKind::Timeout);
|
|
assert_eq!(error.detail(), "send deadline exceeded");
|
|
assert_eq!(error.to_string(), "operation timed out: send deadline exceeded");
|
|
}
|
|
|
|
#[test]
|
|
fn transport_error_kinds_have_stable_human_readable_labels() {
|
|
let cases = [
|
|
(crate::TransportErrorKind::InvalidConfiguration, "invalid configuration"),
|
|
(crate::TransportErrorKind::Connect, "connect failure"),
|
|
(crate::TransportErrorKind::Bind, "bind failure"),
|
|
(crate::TransportErrorKind::Accept, "accept failure"),
|
|
(crate::TransportErrorKind::Timeout, "operation timed out"),
|
|
(crate::TransportErrorKind::MessageTooLarge, "message too large"),
|
|
(crate::TransportErrorKind::Backpressure, "transport backpressure"),
|
|
(crate::TransportErrorKind::Closed, "connection closed"),
|
|
(crate::TransportErrorKind::Io, "I/O failure"),
|
|
(crate::TransportErrorKind::Protocol, "protocol failure"),
|
|
(crate::TransportErrorKind::Aborted, "operation aborted"),
|
|
];
|
|
for (kind, expected) in cases {
|
|
assert_eq!(kind.to_string(), expected);
|
|
}
|
|
}
|