use std::error::Error; use tokio::sync::mpsc; use tokio::sync::mpsc::Sender; use tokio::task; use crate::args::Args; use crate::data::BotType; use crate::human_player_ws::ServerMessage; use crate::server::start_server; use crate::test::bot_client::{ClientEndResult, RunMode}; use crate::test::{bot_client, TestPort}; use crate::utils::network_utils::wait_for_port; #[tokio::test] async fn invalid_accept_code() { 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::InviteModeInvalidCode, ))); wait_for_port(TestPort::InviteModeInvalidCode.port()).await; let res = bot_client::BotClient::new(TestPort::InviteModeInvalidCode.as_url()) .with_run_mode(RunMode::AcceptInvite { code: "BadCode".to_string(), }) .run_client() .await .unwrap(); assert_eq!(res, ClientEndResult::InvalidInviteCode) }) .await; } async fn run_other_invite_side( sender: Sender>>, port: TestPort, code: String, play_as_bot_type: BotType, number_plays: usize, ) { let res = bot_client::BotClient::new(port.as_url()) .with_run_mode(RunMode::AcceptInvite { code }) .with_play_as_bot_type(play_as_bot_type) .with_number_plays(number_plays) .run_client() .await; sender.send(res).await.unwrap() } #[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::InviteModeFullGame))); wait_for_port(TestPort::InviteModeFullGame.port()).await; let (sender, mut receiver) = mpsc::channel(1); let res = bot_client::BotClient::new(TestPort::InviteModeFullGame.as_url()) .with_run_mode(RunMode::CreateInvite) .with_server_msg_callback(move |msg| { if let ServerMessage::SetInviteCode { code } = msg { task::spawn_local(run_other_invite_side( sender.clone(), TestPort::InviteModeFullGame, code.clone(), BotType::Random, 1, )); } }) .run_client() .await .unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); let other_side_res = receiver.recv().await.unwrap().unwrap(); assert!(matches!(other_side_res, ClientEndResult::Finished { .. })); }) .await; } #[tokio::test] async fn first_player_win() { 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::InviteModeFirstPlayerWin, ))); wait_for_port(TestPort::InviteModeFirstPlayerWin.port()).await; let (sender, mut receiver) = mpsc::channel(1); let res = bot_client::BotClient::new(TestPort::InviteModeFirstPlayerWin.as_url()) .with_run_mode(RunMode::CreateInvite) .with_play_as_bot_type(BotType::Smart) .with_number_plays(3) .with_server_msg_callback(move |msg| { if let ServerMessage::SetInviteCode { code } = msg { task::spawn_local(run_other_invite_side( sender.clone(), TestPort::InviteModeFirstPlayerWin, code.clone(), BotType::Linear, 3, )); } }) .run_client() .await .unwrap(); let other_side_res = receiver.recv().await.unwrap().unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); assert!(matches!(other_side_res, ClientEndResult::Finished { .. })); match (res, other_side_res) { ( ClientEndResult::Finished { number_defeats: d1, number_victories: v1, }, ClientEndResult::Finished { number_defeats: d2, number_victories: v2, }, ) => { assert_eq!(d1, v2); assert_eq!(v1, d2); assert!(v1 > 1); } (_, _) => unreachable!(), } }) .await; } #[tokio::test] async fn second_player_win() { 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::InviteModeSecondPlayerWin, ))); wait_for_port(TestPort::InviteModeSecondPlayerWin.port()).await; let (sender, mut receiver) = mpsc::channel(1); let res = bot_client::BotClient::new(TestPort::InviteModeSecondPlayerWin.as_url()) .with_run_mode(RunMode::CreateInvite) .with_play_as_bot_type(BotType::Linear) .with_number_plays(3) .with_server_msg_callback(move |msg| { if let ServerMessage::SetInviteCode { code } = msg { task::spawn_local(run_other_invite_side( sender.clone(), TestPort::InviteModeSecondPlayerWin, code.clone(), BotType::Smart, 3, )); } }) .run_client() .await .unwrap(); let other_side_res = receiver.recv().await.unwrap().unwrap(); assert!(matches!(res, ClientEndResult::Finished { .. })); assert!(matches!(other_side_res, ClientEndResult::Finished { .. })); match (res, other_side_res) { ( ClientEndResult::Finished { number_defeats: d1, number_victories: v1, }, ClientEndResult::Finished { number_defeats: d2, number_victories: v2, }, ) => { assert_eq!(d1, v2); assert_eq!(v1, d2); assert!(v2 > 1); } (_, _) => unreachable!(), } }) .await; }