use character_service::character_service::character::character_service_server::CharacterService; use character_service::character_service::character::{ CreateCharacterRequest, DeleteCharacterRequest, GetCharacterListRequest, GetCharacterRequest, }; use character_service::character_service::MyCharacterService; use mockall::predicate::*; use mockall::predicate::eq; use mockall::mock; // Wrapper for the mock to implement the trait struct MockWrapper(MockCharacterDbClientTrait); impl character_service::character_db_client::CharacterDbClient for MockWrapper { async fn get_character_list(&mut self, user_id: &str) -> Result> { self.0.get_character_list(user_id).await } async fn create_character(&mut self, user_id: &str, name: &str, race: i32, face: i32, hair: i32, stone: i32) -> Result> { self.0.create_character(user_id, name, race, face, hair, stone).await } async fn delete_character(&mut self, user_id: &str, char_id: &str, delete_type: i32) -> Result> { self.0.delete_character(user_id, char_id, delete_type).await } async fn get_character(&mut self, user_id: &str, char_id: &str) -> Result> { self.0.get_character(user_id, char_id).await } } use std::sync::Arc; use tonic::{Request, Status}; // Define a trait for the CharacterDbClient to make it mockable #[mockall::automock] trait CharacterDbClientTrait { async fn get_character_list(&mut self, user_id: &str) -> Result>; async fn create_character(&mut self, user_id: &str, name: &str, race: i32, face: i32, hair: i32, stone: i32) -> Result>; async fn delete_character(&mut self, user_id: &str, char_id: &str, delete_type: i32) -> Result>; async fn get_character(&mut self, user_id: &str, char_id: &str) -> Result>; } #[tokio::test] async fn test_get_character_list() { // Create a mock CharacterDbClient let mut mock_client = MockCharacterDbClientTrait::new(); // Set up expectations mock_client .expect_get_character_list() .with(eq("test_user")) .times(1) .returning(|_| { Ok(character_service::database::CharacterListResponse { characters: vec![ character_service::database::Character { id: 1, user_id: "test_user".to_string(), name: "Character1".to_string(), money: 1000, inventory: "{\"items\":[]}".to_string(), stats: "{\"level\":1}".to_string(), skills: "{\"skills\":[]}".to_string(), looks: "{\"race\":0}".to_string(), position: "{\"x\":0,\"y\":0,\"z\":0}".to_string(), deleted_at: "".to_string(), }, character_service::database::Character { id: 2, user_id: "test_user".to_string(), name: "Character2".to_string(), money: 2000, inventory: "{\"items\":[]}".to_string(), stats: "{\"level\":5}".to_string(), skills: "{\"skills\":[]}".to_string(), looks: "{\"race\":1}".to_string(), position: "{\"x\":10,\"y\":10,\"z\":0}".to_string(), deleted_at: "".to_string(), }, ], }) }); // Create a wrapper struct that implements CharacterDbClient struct MockWrapper(MockCharacterDbClientTrait); impl std::ops::Deref for MockWrapper { type Target = MockCharacterDbClientTrait; fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for MockWrapper { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl Clone for MockWrapper { fn clone(&self) -> Self { panic!("Mock should not be cloned") } } // Create the service with the mock client let service = MyCharacterService { character_db_client: Arc::new(MockWrapper(mock_client)), }; // Create a request let request = Request::new(GetCharacterListRequest { user_id: "test_user".to_string(), }); // Call the service method let response = service.get_character_list(request).await.unwrap(); let response = response.into_inner(); // Verify the response assert_eq!(response.characters.len(), 2); assert_eq!(response.characters[0].name, "Character1"); assert_eq!(response.characters[1].name, "Character2"); } #[tokio::test] async fn test_create_character() { // Create a mock CharacterDbClient let mut mock_client = MockCharacterDbClientTrait::new(); // Set up expectations mock_client .expect_create_character() .with(eq("test_user"), eq("NewCharacter"), eq(0), eq(1), eq(2), eq(3)) .times(1) .returning(|_, _, _, _, _, _| { Ok(character_service::database::CreateCharacterResponse { result: 0, character_id: 3, }) }); // Create the service with the mock client let service = MyCharacterService { character_db_client: Arc::new(MockWrapper(mock_client)), }; // Create a request let request = Request::new(CreateCharacterRequest { user_id: "test_user".to_string(), name: "NewCharacter".to_string(), race: 0, face: 1, hair: 2, stone: 3, }); // Call the service method let response = service.create_character(request).await.unwrap(); let response = response.into_inner(); // Verify the response assert_eq!(response.result, 0); } #[tokio::test] async fn test_delete_character() { // Create a mock CharacterDbClient let mut mock_client = MockCharacterDbClientTrait::new(); // Set up expectations mock_client .expect_delete_character() .with(eq("test_user"), eq("3"), eq(1)) .times(1) .returning(|_, _, _| { Ok(character_service::database::DeleteCharacterResponse { remaining_time: 86400, // 24 hours in seconds name: "DeletedCharacter".to_string(), }) }); // Create the service with the mock client let service = MyCharacterService { character_db_client: Arc::new(MockWrapper(mock_client)), }; // Create a request let request = Request::new(DeleteCharacterRequest { user_id: "test_user".to_string(), char_id: "3".to_string(), delete_type: 1, }); // Call the service method let response = service.delete_character(request).await.unwrap(); let response = response.into_inner(); // Verify the response assert_eq!(response.remaining_time, 86400); assert_eq!(response.name, "DeletedCharacter"); } #[tokio::test] async fn test_get_character() { // Create a mock CharacterDbClient let mut mock_client = MockCharacterDbClientTrait::new(); // Set up expectations mock_client .expect_get_character() .with(eq("test_user"), eq("1")) .times(1) .returning(|_, _| { Ok(character_service::database::Character { id: 1, user_id: "test_user".to_string(), name: "Character1".to_string(), money: 1000, inventory: "{\"items\":[{\"id\":1,\"count\":10}]}".to_string(), stats: "{\"level\":10,\"hp\":100,\"mp\":50}".to_string(), skills: "{\"skills\":[{\"id\":1,\"level\":5}]}".to_string(), looks: "{\"race\":0,\"face\":1,\"hair\":2}".to_string(), position: "{\"x\":100,\"y\":200,\"z\":0,\"map\":1}".to_string(), deleted_at: "".to_string(), }) }); // Create the service with the mock client let service = MyCharacterService { character_db_client: Arc::new(MockWrapper(mock_client)), }; // Create a request let request = Request::new(GetCharacterRequest { user_id: "test_user".to_string(), char_id: "1".to_string(), }); // Call the service method let response = service.get_character(request).await.unwrap(); let response = response.into_inner(); // Verify the response let character = response.character.unwrap(); assert_eq!(character.name, "Character1"); assert_eq!(character.money, 1000); // Verify JSON fields were parsed correctly assert!(character.inventory.contains("items")); assert!(character.stats.contains("level")); assert!(character.skills.contains("skills")); assert!(character.looks.contains("race")); assert!(character.position.contains("map")); }