import sys import os import pytest from unittest.mock import patch sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from app.services.stats import ( _map_stats, get_current_season, get_season_avg, get_last_n, get_splits, ) class TestMapStats: def test_maps_all_nba_api_columns(self): row = { "PTS": 26.3, "REB": 12.4, "AST": 9.1, "FG3M": 1.1, "BLK": 0.7, "STL": 1.4, "TOV": 3.2, "MIN": 34.2, "GP": 65, } result = _map_stats(row) assert result["points"] == 26.3 assert result["rebounds"] == 12.4 assert result["assists"] == 9.1 assert result["threes"] == 1.1 assert result["blocks"] == 0.7 assert result["steals"] == 1.4 assert result["turnovers"] == 3.2 assert result["minutes"] == 34.2 assert result["games_played"] == 65.0 def test_computes_pra(self): row = {"PTS": 25.0, "REB": 10.0, "AST": 8.0} result = _map_stats(row) assert result["pra"] == 43.0 def test_handles_missing_stats(self): row = {} result = _map_stats(row) assert result["pra"] == 0 assert "points" not in result def test_rounds_to_one_decimal(self): row = {"PTS": 26.333333} result = _map_stats(row) assert result["points"] == 26.3 class TestGetCurrentSeason: def test_current_season_format(self): season = get_current_season() assert len(season) == 7 assert "-" in season year = int(season[:4]) suffix = int(season[5:]) assert suffix == (year + 1) % 100 class TestGetSeasonAvg: def test_returns_season_averages(self, mock_nba_api): result = get_season_avg("Nikola Jokic", season="2025-26") assert result is not None assert result["player"] == "Nikola Jokic" assert result["team"] == "DEN" assert result["stats"]["points"] == 26.3 assert result["stats"]["pra"] == 47.8 assert result["source"] == "live" def test_filters_by_stat_type(self, mock_nba_api): result = get_season_avg("Nikola Jokic", stat_type="points", season="2025-26") assert list(result["stats"].keys()) == ["points"] def test_returns_cache_when_available(self): cached = { "player": "Nikola Jokic", "player_id": 203999, "team": "DEN", "season": "2025-26", "source": "live", "stats": {"points": 26.3}, } with patch("app.services.stats.cache_get", return_value=cached), \ patch("app.utils.player_map.cache_get", return_value=None), \ patch("app.utils.player_map.cache_set"), \ patch("app.utils.player_map.players.get_players", return_value=[ {"id": 203999, "full_name": "Nikola Jokic", "is_active": True} ]), \ patch("app.services.stats.time.sleep"): result = get_season_avg("Nikola Jokic", season="2025-26") assert result["source"] == "cache" class TestGetLastN: def test_returns_last_n_averages(self, mock_nba_api): result = get_last_n("Nikola Jokic", n=5) assert result is not None assert result["last_n"] == 5 assert result["stats"]["games_played"] == 5.0 assert result["source"] == "live" assert result["stats"]["points"] == 26.0 def test_clamps_n_to_max_30(self, mock_nba_api): result = get_last_n("Nikola Jokic", n=50) assert result["last_n"] == 30 class TestGetSplits: def test_home_away_split(self, mock_nba_api): result = get_splits("Nikola Jokic", "points", "home_away") assert result is not None assert "home" in result["splits"] assert "away" in result["splits"] assert result["splits"]["home"]["games"] == 3 assert result["splits"]["away"]["games"] == 2 def test_rest_days_split(self, mock_nba_api): result = get_splits("Nikola Jokic", "points", "rest_days") assert result is not None assert "b2b" in result["splits"] assert "1_day_rest" in result["splits"] assert "2_plus_days_rest" in result["splits"] def test_vs_team_split(self, mock_nba_api): result = get_splits("Nikola Jokic", "points", "vs_team", opponent="LAL") assert result is not None assert "vs_opponent" in result["splits"] assert "vs_all_others" in result["splits"] assert result["splits"]["vs_opponent"]["games"] == 2 def test_vs_team_requires_opponent(self, mock_nba_api): result = get_splits("Nikola Jokic", "points", "vs_team", opponent=None) assert result is None class TestPlayerNotFound: @patch("app.utils.player_map.players.get_players", return_value=[]) @patch("app.utils.player_map.cache_get", return_value=None) @patch("app.utils.player_map.cache_set") def test_season_avg_returns_none(self, mock_set, mock_get, mock_players): result = get_season_avg("Nonexistent Player") assert result is None @patch("app.utils.player_map.players.get_players", return_value=[]) @patch("app.utils.player_map.cache_get", return_value=None) @patch("app.utils.player_map.cache_set") def test_last_n_returns_none(self, mock_set, mock_get, mock_players): result = get_last_n("Nonexistent Player") assert result is None