diff --git a/server/src/connection.rs b/server/src/connection.rs index dd70056..715ae88 100644 --- a/server/src/connection.rs +++ b/server/src/connection.rs @@ -167,3 +167,52 @@ async fn cleanup_player( println!("Cleaned up player {}", player_id); } + +#[cfg(test)] +mod tests { + use super::*; + use uuid::Uuid; + + #[tokio::test] + async fn test_send_message_to_nonexistent_player() { + let connections = new_connection_map(); + let player_id = Uuid::new_v4(); + + let result = send_message_to_player(&connections, player_id, "test message").await; + assert!(result.is_ok(), "Should handle missing player gracefully"); + } + + #[tokio::test] + async fn test_broadcast_to_empty_connections() { + let connections = new_connection_map(); + + broadcast_to_all(&connections, "test broadcast").await; + + let conn_map = connections.lock().await; + assert!(conn_map.is_empty(), "Connections should still be empty"); + } + + #[tokio::test] + async fn test_connection_cleanup() { + let connections = new_connection_map(); + let matches = new_match_map(); + let waiting_queue = new_waiting_queue(); + + let player_id = Uuid::new_v4(); + + { + waiting_queue.lock().await.push_back(player_id); + assert_eq!(waiting_queue.lock().await.len(), 1); + } + + cleanup_player(player_id, &connections, &matches, &waiting_queue).await; + + { + let queue = waiting_queue.lock().await; + assert!( + !queue.contains(&player_id), + "Player should be removed from waiting queue" + ); + } + } +} diff --git a/server/src/events.rs b/server/src/events.rs index 0d836b5..8cc43a4 100644 --- a/server/src/events.rs +++ b/server/src/events.rs @@ -75,3 +75,52 @@ impl Default for EventSystem { Self::new() } } + +#[cfg(test)] +mod tests { + use super::*; + use uuid::Uuid; + + #[tokio::test] + async fn test_event_system_send_and_receive() { + let event_system = EventSystem::new(); + let player_id = Uuid::new_v4(); + + let join_event = ClientEvent::Join { + username: "test_user".to_string(), + }; + + let send_result = event_system.send_event(player_id, join_event).await; + assert!(send_result.is_ok(), "Should send event successfully"); + + let received = event_system.next_event().await; + assert!(received.is_some(), "Should receive sent event"); + + let (received_id, received_event) = received.unwrap(); + assert_eq!(received_id, player_id, "Should receive correct player ID"); + + match received_event { + ClientEvent::Join { username } => { + assert_eq!(username, "test_user", "Should receive correct username"); + } + _ => panic!("Should receive Join event"), + } + } + + #[tokio::test] + async fn test_event_system_clone() { + let event_system1 = EventSystem::new(); + let event_system2 = event_system1.clone(); + + let player_id = Uuid::new_v4(); + let event = ClientEvent::FindMatch; + + event_system1.send_event(player_id, event).await.unwrap(); + + let received = event_system2.next_event().await; + assert!( + received.is_some(), + "Cloned event system should receive events" + ); + } +} diff --git a/server/src/main.rs b/server/src/main.rs index ecc9b6f..0d35baf 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,7 +1,6 @@ mod connection; mod events; mod matchmaking; - use tokio::net::TcpListener; #[tokio::main] diff --git a/server/src/matchmaking.rs b/server/src/matchmaking.rs index c2995ba..4f4cc27 100644 --- a/server/src/matchmaking.rs +++ b/server/src/matchmaking.rs @@ -110,3 +110,93 @@ impl MatchmakingSystem { println!("Match created: {} (white) vs {} (black)", white, black); } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::events::EventSystem; + use uuid::Uuid; + + use crate::connection::new_connection_map; + use crate::connection::new_match_map; + use crate::connection::new_waiting_queue; + + #[tokio::test] + async fn test_matchmaking_creates_matches() { + let connections = new_connection_map(); + let matches = new_match_map(); + let waiting_queue = new_waiting_queue(); + let event_system = EventSystem::new(); + + let matchmaking = MatchmakingSystem::new( + connections.clone(), + matches.clone(), + waiting_queue.clone(), + event_system.clone(), + ); + + let player1 = Uuid::new_v4(); + let player2 = Uuid::new_v4(); + + { + waiting_queue.lock().await.push_back(player1); + waiting_queue.lock().await.push_back(player2); + } + + matchmaking.try_create_match().await; + + { + let matches_map = matches.lock().await; + assert_eq!(matches_map.len(), 1, "Should create one match"); + + let game_match = matches_map.values().next().unwrap(); + assert!(game_match.player_white == player1 || game_match.player_white == player2); + assert!(game_match.player_black == player1 || game_match.player_black == player2); + assert_ne!( + game_match.player_white, game_match.player_black, + "Players should be different" + ); + } + + { + let queue = waiting_queue.lock().await; + assert!( + queue.is_empty(), + "Waiting queue should be empty after matchmaking" + ); + } + } + + #[tokio::test] + async fn test_matchmaking_with_odd_players() { + let connections = new_connection_map(); + let matches = new_match_map(); + let waiting_queue = new_waiting_queue(); + let event_system = EventSystem::new(); + + let matchmaking = MatchmakingSystem::new( + connections.clone(), + matches.clone(), + waiting_queue.clone(), + event_system.clone(), + ); + + let player1 = Uuid::new_v4(); + { + waiting_queue.lock().await.push_back(player1); + } + + matchmaking.try_create_match().await; + + { + let matches_map = matches.lock().await; + assert!( + matches_map.is_empty(), + "Should not create match with only one player" + ); + + let queue = waiting_queue.lock().await; + assert_eq!(queue.len(), 1, "Should keep single player in queue"); + } + } +}