from datetime import date from decimal import Decimal from django.test import TestCase from django.urls import reverse from .models import Competition, Player, PlayerSeason, PlayerSeasonStats, Role, Season, Specialty, Team class ScoutingSearchViewsTests(TestCase): @classmethod def setUpTestData(cls): cls.role_playmaker = Role.objects.create(name="playmaker", slug="playmaker") cls.role_3d = Role.objects.create(name="3-and-D", slug="3-and-d") cls.specialty_defense = Specialty.objects.create(name="defense", slug="defense") cls.specialty_offball = Specialty.objects.create(name="off ball", slug="off-ball") cls.comp_a = Competition.objects.create(name="League A") cls.comp_b = Competition.objects.create(name="League B") cls.team_a = Team.objects.create(name="Team A", country="IT") cls.team_b = Team.objects.create(name="Team B", country="IT") cls.season_2025 = Season.objects.create(name="2025-2026", start_year=2025, end_year=2026) cls.season_2024 = Season.objects.create(name="2024-2025", start_year=2024, end_year=2025) cls.player_pg = Player.objects.create( full_name="Marco Guard", birth_date=date(2002, 1, 1), position="PG", height_cm=Decimal("188.00"), weight_kg=Decimal("82.00"), nationality="IT", ) cls.player_pg.roles.add(cls.role_playmaker) cls.player_pg.specialties.add(cls.specialty_defense) cls.player_wing = Player.objects.create( full_name="Luca Wing", birth_date=date(1998, 2, 2), position="SF", height_cm=Decimal("201.00"), weight_kg=Decimal("95.00"), ) cls.player_wing.roles.add(cls.role_3d) cls.player_wing.specialties.add(cls.specialty_offball) cls.ctx_pg_good = PlayerSeason.objects.create( player=cls.player_pg, season=cls.season_2025, team=cls.team_a, competition=cls.comp_a, ) PlayerSeasonStats.objects.create( player_season=cls.ctx_pg_good, points=Decimal("16.00"), assists=Decimal("7.50"), steals=Decimal("1.80"), turnovers=Decimal("2.10"), blocks=Decimal("0.30"), efg_pct=Decimal("53.20"), ts_pct=Decimal("58.10"), plus_minus=Decimal("4.20"), offensive_rating=Decimal("112.00"), defensive_rating=Decimal("104.00"), ) cls.ctx_pg_other = PlayerSeason.objects.create( player=cls.player_pg, season=cls.season_2024, team=cls.team_b, competition=cls.comp_b, ) PlayerSeasonStats.objects.create( player_season=cls.ctx_pg_other, points=Decimal("10.00"), assists=Decimal("4.00"), steals=Decimal("1.00"), turnovers=Decimal("3.50"), blocks=Decimal("0.20"), efg_pct=Decimal("48.00"), ts_pct=Decimal("50.00"), plus_minus=Decimal("-2.00"), offensive_rating=Decimal("101.00"), defensive_rating=Decimal("112.00"), ) cls.ctx_wing = PlayerSeason.objects.create( player=cls.player_wing, season=cls.season_2025, team=cls.team_b, competition=cls.comp_a, ) PlayerSeasonStats.objects.create( player_season=cls.ctx_wing, points=Decimal("14.00"), assists=Decimal("2.00"), steals=Decimal("1.20"), turnovers=Decimal("1.90"), blocks=Decimal("0.70"), efg_pct=Decimal("55.00"), ts_pct=Decimal("60.00"), plus_minus=Decimal("1.50"), offensive_rating=Decimal("108.00"), defensive_rating=Decimal("106.00"), ) def test_player_list_page_loads(self): response = self.client.get(reverse("scouting:player_list")) self.assertEqual(response.status_code, 200) self.assertContains(response, "Scout Search") def test_player_detail_page_loads(self): response = self.client.get(reverse("scouting:player_detail", args=[self.player_pg.id])) self.assertEqual(response.status_code, 200) self.assertContains(response, self.player_pg.full_name) def test_filter_by_player_level_fields(self): response = self.client.get( reverse("scouting:player_list"), {"position": "PG", "role": self.role_playmaker.id, "specialty": self.specialty_defense.id}, ) self.assertContains(response, self.player_pg.full_name) self.assertNotContains(response, self.player_wing.full_name) def test_filter_by_context_fields_and_stats(self): response = self.client.get( reverse("scouting:player_list"), { "competition": self.comp_a.id, "season": self.season_2025.id, "team": self.team_a.id, "min_ts_pct": "57", }, ) self.assertContains(response, self.player_pg.full_name) self.assertNotContains(response, self.player_wing.full_name) def test_no_false_positive_from_different_context_rows(self): response = self.client.get( reverse("scouting:player_list"), { "team": self.team_b.id, "season": self.season_2024.id, "min_ts_pct": "57", }, ) self.assertNotContains(response, self.player_pg.full_name) def test_combined_pg_under_age_with_assists(self): response = self.client.get( reverse("scouting:player_list"), { "position": "PG", "max_age": "25", "min_assists": "7", }, ) self.assertContains(response, self.player_pg.full_name) self.assertNotContains(response, self.player_wing.full_name) def test_combined_team_and_defensive_rating_quality_filter(self): response = self.client.get( reverse("scouting:player_list"), { "team": self.team_a.id, "max_defensive_rating": "105", }, ) self.assertContains(response, self.player_pg.full_name) self.assertNotContains(response, self.player_wing.full_name)