use tokio::task; use crate::args::Args; use crate::data::{BoatsLayout, BotType, Coordinates, GameRules}; use crate::human_player_ws::ServerMessage; use crate::server::start_server; use crate::test::bot_client::ClientEndResult; use crate::test::play_utils::check_no_replay_on_hit; use crate::test::{bot_client, TestPort}; use crate::utils::network_utils::wait_for_port; fn check_strikes_are_linear(msg: &mut ServerMessage) { if let ServerMessage::RequestFire { status } = msg { let mut in_fire_location = true; for y in 0..status.rules.map_height { for x in 0..status.rules.map_width { let c = Coordinates::new(x as i32, y as i32); if in_fire_location { in_fire_location = status.your_map.did_fire_at_location(c); } else if status.your_map.did_fire_at_location(c) { println!("Your map:"); status.print_your_map(); println!("Opponent map:"); status.print_opponent_map(); panic!("Found invalid fire location for linear bot!"); } } } } } #[tokio::test] async fn full_game() { let _ = env_logger::builder().is_test(true).try_init(); let local_set = task::LocalSet::new(); local_set .run_until(async move { task::spawn_local(start_server(Args::for_test(TestPort::LinearBotFullGame))); wait_for_port(TestPort::LinearBotFullGame.port()).await; let res = bot_client::BotClient::new(TestPort::LinearBotFullGame.as_url()) .with_rules(GameRules::random_players_rules().with_bot_type(BotType::Linear)) .with_server_msg_callback(check_strikes_are_linear) .run_client() .await .unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); }) .await; } #[tokio::test] async fn full_game_no_replay_on_hit() { let _ = env_logger::builder().is_test(true).try_init(); let local_set = task::LocalSet::new(); local_set .run_until(async move { task::spawn_local(start_server(Args::for_test( TestPort::LinearBotNoReplayOnHit, ))); wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await; let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url()) .with_rules( GameRules::random_players_rules() .with_player_continue_on_hit(false) .with_bot_type(BotType::Linear), ) .with_server_msg_callback(check_no_replay_on_hit) .run_client() .await .unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); }) .await; } #[tokio::test] async fn full_game_no_replay_on_hit_two() { let _ = env_logger::builder().is_test(true).try_init(); let local_set = task::LocalSet::new(); local_set .run_until(async move { task::spawn_local(start_server(Args::for_test( TestPort::LinearBotNoReplayOnHit, ))); wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await; let rules = GameRules::random_players_rules() .with_player_continue_on_hit(false) .with_bot_type(BotType::Linear); let layout = BoatsLayout::layout_for_boats_at_beginning_of_map(&rules).unwrap(); let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url()) .with_rules(rules.clone()) .with_layout(layout) .with_server_msg_callback(check_no_replay_on_hit) .run_client() .await .unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); }) .await; } #[tokio::test] async fn full_game_with_replay_on_hit() { let _ = env_logger::builder().is_test(true).try_init(); let local_set = task::LocalSet::new(); local_set .run_until(async move { task::spawn_local(start_server(Args::for_test( TestPort::LinearBotNoReplayOnHit, ))); wait_for_port(TestPort::LinearBotNoReplayOnHit.port()).await; let rules = GameRules::random_players_rules() .with_player_continue_on_hit(true) .with_bot_type(BotType::Linear); let layout = BoatsLayout::layout_for_boats_at_beginning_of_map(&rules).unwrap(); let res = bot_client::BotClient::new(TestPort::LinearBotNoReplayOnHit.as_url()) .with_rules(rules.clone()) .with_layout(layout) .with_server_msg_callback(|msg| { if let ServerMessage::LostGame { status } | ServerMessage::WonGame { status } = msg { assert!( status.opponent_map.number_of_fires() < status.your_map.number_of_fires() ); } }) .run_client() .await .unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); }) .await; }