Files
games/crates/common/game-realtime-transport-lib/unit_tests/contract.rs
2026-09-21 17:21:25 +02:00

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);
}
}