Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| import pytest | |
| from ingest.sofascore.enrich_mapper import ( | |
| flatten_enrich_features, | |
| map_h2h, | |
| map_incidents_extended, | |
| map_pregame_form, | |
| map_team_streaks, | |
| ) | |
| from ingest.sofascore.enrich import build_enrich_payload | |
| class FakeEnrichClient: | |
| def __init__( | |
| self, | |
| event: dict, | |
| pregame_form: dict | None, | |
| team_streaks: dict | None, | |
| h2h: dict | None, | |
| incidents: dict | None, | |
| ): | |
| self._event = event | |
| self._pregame_form = pregame_form | |
| self._team_streaks = team_streaks | |
| self._h2h = h2h | |
| self._incidents = incidents | |
| def event(self, event_id: int) -> dict: | |
| return self._event | |
| def event_pregame_form(self, event_id: int) -> dict: | |
| if self._pregame_form is None: | |
| raise RuntimeError("no pregame form") | |
| return self._pregame_form | |
| def event_team_streaks(self, event_id: int) -> dict: | |
| if self._team_streaks is None: | |
| raise RuntimeError("no team streaks") | |
| return self._team_streaks | |
| def event_h2h(self, event_id: int) -> dict: | |
| if self._h2h is None: | |
| raise RuntimeError("no h2h") | |
| return self._h2h | |
| def event_incidents(self, event_id: int) -> dict: | |
| if self._incidents is None: | |
| raise RuntimeError("no incidents") | |
| return self._incidents | |
| def test_map_pregame_form_basic(): | |
| payload = { | |
| "homeTeam": { | |
| "position": 1, | |
| "value": 25, | |
| "avgRating": 7.2, | |
| "form": ["W", "W", "D", "L", "W"], | |
| }, | |
| "awayTeam": { | |
| "position": 5, | |
| "value": 15, | |
| "avgRating": 6.8, | |
| "form": ["L", "D", "D", "W", "L"], | |
| }, | |
| } | |
| mapped = map_pregame_form(payload) | |
| assert mapped["home_position_competition"] == 1 | |
| assert mapped["away_position_competition"] == 5 | |
| assert mapped["home_points_competition"] == 25 | |
| assert mapped["away_points_competition"] == 15 | |
| assert mapped["home_avgrating_last5"] == 7.2 | |
| assert mapped["away_avgrating_last5"] == 6.8 | |
| assert mapped["home_form_points_last5"] == 10 # 3+3+1+0+3 | |
| assert mapped["away_form_points_last5"] == 5 # 0+1+1+3+0 | |
| assert mapped["home_form_wins_last5"] == 3 | |
| assert mapped["away_form_wins_last5"] == 1 | |
| assert mapped["position_diff"] == -4 # 1 - 5 | |
| assert mapped["points_diff"] == 10 # 25 - 15 | |
| assert mapped["form_points_diff"] == 5 # 10 - 5 | |
| def test_map_pregame_form_empty_form(): | |
| payload = { | |
| "homeTeam": {"position": 3, "value": 10, "avgRating": 6.5}, | |
| "awayTeam": {"position": 8, "value": 5, "avgRating": 6.0}, | |
| } | |
| mapped = map_pregame_form(payload) | |
| # Quando não há form, as métricas de form não são adicionadas | |
| assert "home_form_points_last5" not in mapped | |
| assert mapped["position_diff"] == -5 | |
| def test_map_team_streaks_unbeaten_and_wins(): | |
| payload = { | |
| "general": [ | |
| {"team": "home", "name": "Unbeaten", "value": 8, "continued": True}, | |
| {"team": "away", "name": "Wins", "value": 3, "continued": True}, | |
| {"team": "home", "name": "Clean sheets", "value": 4, "continued": False}, | |
| ] | |
| } | |
| mapped = map_team_streaks(payload) | |
| assert mapped["home_streak_unbeaten"] == 8 | |
| assert mapped["away_streak_wins"] == 3 | |
| assert mapped["home_streak_clean_sheets"] == 4 | |
| assert mapped["home_streak_continued"] == 0 # último streak do home tem continued=False | |
| assert mapped["streak_unbeaten_diff"] == 8 # 8 - 0 | |
| assert mapped["streak_wins_diff"] == -3 # 0 - 3 | |
| def test_map_h2h_basic(): | |
| payload = { | |
| "teamDuel": { | |
| "homeWins": 10, | |
| "awayWins": 5, | |
| "draws": 3, | |
| }, | |
| "matches": [ | |
| {"winnerCode": "1"}, | |
| {"winnerCode": "3"}, | |
| {"winnerCode": "2"}, | |
| {"winnerCode": "1"}, | |
| {"winnerCode": "1"}, | |
| ], | |
| } | |
| mapped = map_h2h(payload) | |
| assert mapped["h2h_home_wins_all"] == 10 | |
| assert mapped["h2h_away_wins_all"] == 5 | |
| assert mapped["h2h_draws_all"] == 3 | |
| assert mapped["h2h_total_all"] == 18 | |
| assert mapped["h2h_home_win_rate"] == pytest.approx(10 / 18, abs=0.001) | |
| assert mapped["h2h_home_wins_recent5"] == 3 | |
| assert mapped["h2h_away_wins_recent5"] == 1 | |
| assert mapped["h2h_draws_recent5"] == 1 | |
| def test_map_h2h_empty(): | |
| mapped = map_h2h({}) | |
| assert mapped["h2h_total_all"] == 0 | |
| assert mapped["h2h_home_win_rate"] == 0.0 | |
| def test_map_incidents_extended_temporal(): | |
| payload = { | |
| "incidents": [ | |
| {"incidentType": "goal", "isHome": True, "time": 15}, | |
| {"incidentType": "goal", "isHome": False, "time": 35}, | |
| {"incidentType": "goal", "isHome": True, "time": 55}, | |
| {"incidentType": "goal", "isHome": False, "time": 75}, | |
| {"incidentType": "card", "incidentClass": "red", "isHome": True, "time": 45}, | |
| ] | |
| } | |
| mapped = map_incidents_extended(payload) | |
| assert mapped["incident_first_goal_minute"] == 15 | |
| assert mapped["incident_goals_ht_home"] == 1 # só o de 15 (55 é > 45) | |
| assert mapped["incident_goals_ht_away"] == 1 # 35 | |
| assert mapped["incident_goals_ft_home"] == 1 # 55 | |
| assert mapped["incident_goals_ft_away"] == 1 # 75 | |
| assert mapped["incident_red_cards_before_60_home"] == 1 # 45 < 60 | |
| assert mapped["incident_red_cards_before_60_away"] == 0 | |
| def test_flatten_enrich_features_combined(): | |
| row = flatten_enrich_features( | |
| event_id=99, | |
| home_team="Brasil", | |
| away_team="Argentina", | |
| match_date="2026-06-15", | |
| pregame_form={ | |
| "homeTeam": {"position": 1, "value": 30, "avgRating": 7.5, "form": ["W", "W", "W", "W", "W"]}, | |
| "awayTeam": {"position": 2, "value": 25, "avgRating": 7.0, "form": ["W", "W", "D", "W", "L"]}, | |
| }, | |
| team_streaks={"general": [{"team": "home", "name": "Unbeaten", "value": 10, "continued": True}]}, | |
| h2h={"teamDuel": {"homeWins": 5, "awayWins": 3, "draws": 2}}, | |
| incidents=None, | |
| ) | |
| assert row["event_id"] == 99 | |
| assert row["home_team"] == "Brasil" | |
| assert row["away_team"] == "Argentina" | |
| assert row["home_form_win_pct_last5"] == 1.0 | |
| assert row["away_form_win_pct_last5"] == 0.6 | |
| assert row["home_streak_unbeaten"] == 10 | |
| assert row["h2h_total_all"] == 10 | |
| def test_build_enrich_payload_with_event_id(): | |
| team_map = { | |
| "Brasil": {"sofascore_id": 4748}, | |
| "Argentina": {"sofascore_id": 4819}, | |
| } | |
| event = { | |
| "id": 42, | |
| "homeTeam": {"id": 4748, "name": "Brazil"}, | |
| "awayTeam": {"id": 4819, "name": "Argentina"}, | |
| } | |
| pregame_form = { | |
| "homeTeam": {"position": 1, "value": 20, "avgRating": 7.0, "form": ["W", "D", "W"]}, | |
| "awayTeam": {"position": 3, "value": 12, "avgRating": 6.5, "form": ["L", "W", "D"]}, | |
| } | |
| team_streaks = {"general": []} | |
| h2h = {"teamDuel": {"homeWins": 2, "awayWins": 1, "draws": 1}} | |
| incidents = {"incidents": []} | |
| client = FakeEnrichClient(event, pregame_form, team_streaks, h2h, incidents) | |
| result = build_enrich_payload( | |
| event_id=42, | |
| client=client, | |
| team_map=team_map, | |
| ) | |
| assert result.home_team == "Brasil" | |
| assert result.away_team == "Argentina" | |
| assert result.features["home_position_competition"] == 1 | |
| assert result.features["away_position_competition"] == 3 | |