""" A module for testing the functionalities of `GameService` in the GeoGuessr ecosystem. This module contains a collection of test cases designed to validate the correctness, edge cases, and error handling for various asynchronous methods in the `GameService` class. These include retrieving game details, unfinished games, streak games, activity feeds, recent games, season statistics, and daily challenges. """ import pytest from geoguessr_mcp.models import DailyChallenge, Game, SeasonStats class TestGameService: """Tests for GameService.""" @pytest.mark.asyncio async def test_get_game_details_success( self, game_service, mock_client, mock_game_data, mock_dynamic_response ): """Test successful game details retrieval.""" mock_client.get.return_value = mock_dynamic_response(mock_game_data) game, response = await game_service.get_game_details("ABC123") assert isinstance(game, Game) assert game.token == "ABC123" assert game.map_name == "World" assert game.mode == "standard" assert len(game.rounds) == 5 assert game.total_score == 23200 # Sum of all round scores @pytest.mark.asyncio async def test_get_game_details_with_session_token( self, game_service, mock_client, mock_game_data, mock_dynamic_response ): """Test game details with explicit session token.""" mock_client.get.return_value = mock_dynamic_response(mock_game_data) game, response = await game_service.get_game_details("ABC123", session_token="test_token") call_args = mock_client.get.call_args assert call_args[0][1] == "test_token" @pytest.mark.asyncio async def test_get_game_details_failure(self, game_service, mock_client, mock_dynamic_response): """Test game details retrieval failure.""" mock_client.get.return_value = mock_dynamic_response( {"error": "Game not found"}, success=False, status_code=404 ) with pytest.raises(ValueError, match="Failed to get game details"): await game_service.get_game_details("INVALID") @pytest.mark.asyncio async def test_get_unfinished_games(self, game_service, mock_client, mock_dynamic_response): """Test unfinished games retrieval.""" unfinished_data = [ {"token": "game-1", "map": {"name": "World"}}, {"token": "game-2", "map": {"name": "Europe"}}, ] mock_client.get.return_value = mock_dynamic_response(unfinished_data) response = await game_service.get_unfinished_games() assert response.is_success assert len(response.data) == 2 @pytest.mark.asyncio async def test_get_streak_game(self, game_service, mock_client, mock_dynamic_response): """Test streak game retrieval.""" streak_data = { "token": "streak-123", "currentStreak": 15, "bestStreak": 25, } mock_client.get.return_value = mock_dynamic_response(streak_data) response = await game_service.get_streak_game("streak-123") assert response.is_success assert response.data["currentStreak"] == 15 @pytest.mark.asyncio async def test_get_activity_feed( self, game_service, mock_client, mock_activity_feed_data, mock_dynamic_response ): """Test activity feed retrieval.""" mock_client.get.return_value = mock_dynamic_response(mock_activity_feed_data) response = await game_service.get_activity_feed(count=10, page=0) assert response.is_success assert len(response.data["entries"]) == 3 @pytest.mark.asyncio async def test_get_activity_feed_pagination( self, game_service, mock_client, mock_dynamic_response ): """Test activity feed with pagination.""" page_2_data = {"entries": [{"type": "PlayedGame", "payload": {"gameToken": "old-game"}}]} mock_client.get.return_value = mock_dynamic_response(page_2_data) response = await game_service.get_activity_feed(count=10, page=1) assert response.is_success mock_client.get.assert_called_once() @pytest.mark.asyncio async def test_get_recent_games_success( self, game_service, mock_client, mock_activity_feed_data, mock_game_data, mock_dynamic_response, ): """Test recent games retrieval.""" # First call returns activity feed, subsequent calls return game details mock_client.get.side_effect = [ mock_dynamic_response(mock_activity_feed_data), mock_dynamic_response(mock_game_data), mock_dynamic_response({**mock_game_data, "token": "game-token-2"}), ] games = await game_service.get_recent_games(count=2) assert len(games) == 2 assert all(isinstance(g, Game) for g in games) @pytest.mark.asyncio async def test_get_recent_games_empty_feed( self, game_service, mock_client, mock_dynamic_response ): """Test recent games with empty activity feed.""" mock_client.get.return_value = mock_dynamic_response({"entries": []}) games = await game_service.get_recent_games(count=5) assert len(games) == 0 @pytest.mark.asyncio async def test_get_recent_games_feed_failure( self, game_service, mock_client, mock_dynamic_response ): """Test recent games when feed fails.""" mock_client.get.return_value = mock_dynamic_response({"error": "Failed"}, success=False) games = await game_service.get_recent_games(count=5) assert len(games) == 0 @pytest.mark.asyncio async def test_get_recent_games_skips_failed_game_fetch( self, game_service, mock_client, mock_activity_feed_data, mock_game_data, mock_dynamic_response, ): """Test that failed individual game fetches are skipped.""" mock_client.get.side_effect = [ mock_dynamic_response(mock_activity_feed_data), Exception("Game fetch failed"), # First game fails mock_dynamic_response(mock_game_data), # Second game succeeds ] games = await game_service.get_recent_games(count=2) assert len(games) == 1 @pytest.mark.asyncio async def test_get_season_stats_success( self, game_service, mock_client, mock_season_stats_data, mock_dynamic_response ): """Test season stats retrieval.""" mock_client.get.return_value = mock_dynamic_response(mock_season_stats_data) stats, response = await game_service.get_season_stats() assert isinstance(stats, SeasonStats) assert stats.season_id == "season-2024-1" assert stats.rank == 150 assert stats.rating == 1850 assert stats.division == "Gold" @pytest.mark.asyncio async def test_get_season_stats_failure(self, game_service, mock_client, mock_dynamic_response): """Test season stats failure.""" mock_client.get.return_value = mock_dynamic_response( {"error": "No active season"}, success=False, status_code=404 ) with pytest.raises(ValueError, match="Failed to get season stats"): await game_service.get_season_stats() @pytest.mark.asyncio async def test_get_daily_challenge_today( self, game_service, mock_client, mock_dynamic_response ): """Test daily challenge retrieval for today.""" challenge_data = { "token": "daily-2024-01-15", "map": {"name": "World"}, "date": "2024-01-15", "timeLimit": 180, } mock_client.get.return_value = mock_dynamic_response(challenge_data) challenge, response = await game_service.get_daily_challenge() assert isinstance(challenge, DailyChallenge) assert challenge.token == "daily-2024-01-15" assert challenge.time_limit == 180 @pytest.mark.asyncio async def test_get_daily_challenge_specific_day( self, game_service, mock_client, mock_dynamic_response ): """Test daily challenge for specific day.""" challenge_data = { "token": "daily-2024-01-10", "date": "2024-01-10", } mock_client.get.return_value = mock_dynamic_response(challenge_data) challenge, response = await game_service.get_daily_challenge(day="2024-01-10") assert challenge.date == "2024-01-10" @pytest.mark.asyncio async def test_get_daily_challenge_failure( self, game_service, mock_client, mock_dynamic_response ): """Test daily challenge failure.""" mock_client.get.return_value = mock_dynamic_response( {"error": "Challenge not found"}, success=False, status_code=404 ) with pytest.raises(ValueError, match="Failed to get daily challenge"): await game_service.get_daily_challenge() @pytest.mark.asyncio async def test_get_battle_royale(self, game_service, mock_client, mock_dynamic_response): """Test battle royale game retrieval.""" br_data = { "gameId": "br-123", "players": 10, "status": "in_progress", } mock_client.get.return_value = mock_dynamic_response(br_data) response = await game_service.get_battle_royale("br-123") assert response.is_success assert response.data["players"] == 10 @pytest.mark.asyncio async def test_get_duel(self, game_service, mock_client, mock_dynamic_response): """Test duel game retrieval.""" duel_data = { "duelId": "duel-456", "player1": {"id": "p1", "score": 5000}, "player2": {"id": "p2", "score": 4500}, } mock_client.get.return_value = mock_dynamic_response(duel_data) response = await game_service.get_duel("duel-456") assert response.is_success assert response.data["player1"]["score"] == 5000 @pytest.mark.asyncio async def test_get_tournaments(self, game_service, mock_client, mock_dynamic_response): """Test tournaments retrieval.""" tournaments_data = [ {"id": "t1", "name": "Weekly Tournament", "status": "active"}, {"id": "t2", "name": "Monthly Cup", "status": "upcoming"}, ] mock_client.get.return_value = mock_dynamic_response(tournaments_data) response = await game_service.get_tournaments() assert response.is_success assert len(response.data) == 2