Run Black formatter across 83 files and fix 1514 ruff violations: - E722: bare except → typed exceptions (17 fixes) - E711/E712/E721: comparison style fixes with noqa for SQLAlchemy (44 fixes) - F841: unused variable assignments (70 fixes) - F541/F401: f-string and import cleanup (1383 auto-fixes) Remaining 925 errors are all F403/F405 (star imports) — structural, requires converting to explicit imports in a separate effort. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
288 lines
7.6 KiB
Python
288 lines
7.6 KiB
Python
# Shared fixtures and mocks for players refactor tests
|
|
|
|
import pytest
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, Mock
|
|
import discord
|
|
from discord.ext import commands
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_bot():
|
|
"""Mock Discord bot for testing."""
|
|
bot = AsyncMock(spec=commands.Bot)
|
|
bot.get_cog = Mock(return_value=None)
|
|
bot.add_cog = AsyncMock()
|
|
bot.wait_until_ready = AsyncMock()
|
|
return bot
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_interaction():
|
|
"""Mock Discord interaction for slash commands."""
|
|
interaction = AsyncMock(spec=discord.Interaction)
|
|
interaction.response = AsyncMock()
|
|
interaction.response.defer = AsyncMock()
|
|
interaction.followup = AsyncMock()
|
|
interaction.followup.send = AsyncMock()
|
|
interaction.edit_original_response = AsyncMock()
|
|
|
|
# Mock user
|
|
interaction.user = Mock(spec=discord.Member)
|
|
interaction.user.id = 12345
|
|
interaction.user.mention = "<@12345>"
|
|
|
|
# Mock channel
|
|
interaction.channel = Mock(spec=discord.TextChannel)
|
|
interaction.channel.name = "test-channel"
|
|
interaction.channel.send = AsyncMock()
|
|
|
|
return interaction
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_context():
|
|
"""Mock Discord context for traditional commands."""
|
|
ctx = AsyncMock(spec=commands.Context)
|
|
ctx.send = AsyncMock()
|
|
ctx.author = Mock(spec=discord.Member)
|
|
ctx.author.id = 12345
|
|
ctx.author.mention = "<@12345>"
|
|
ctx.author.roles = []
|
|
ctx.author.guild_permissions = Mock()
|
|
ctx.author.guild_permissions.administrator = False
|
|
|
|
# Mock channel
|
|
ctx.channel = Mock(spec=discord.TextChannel)
|
|
ctx.channel.name = "test-channel"
|
|
ctx.channel.send = AsyncMock()
|
|
|
|
# Mock guild
|
|
ctx.guild = Mock(spec=discord.Guild)
|
|
ctx.guild.roles = []
|
|
|
|
return ctx
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_player():
|
|
"""Sample player data for testing."""
|
|
return {
|
|
"id": 1,
|
|
"player_id": 12345,
|
|
"name": "Test Player",
|
|
"franchise": "BOS",
|
|
"cardset": "MLB 2024",
|
|
"positions": "SS, 2B",
|
|
"rarity": {"name": "All-Star", "value": 3, "color": "1f8b4c"},
|
|
"cost": 150,
|
|
"image": "https://example.com/player.jpg",
|
|
"headshot": "https://example.com/headshot.jpg",
|
|
"batting_card": {
|
|
"contact_r": 85,
|
|
"contact_l": 80,
|
|
"power_r": 70,
|
|
"power_l": 65,
|
|
"vision": 75,
|
|
"speed": 60,
|
|
"stealing": 55,
|
|
},
|
|
"pitching_card": None,
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_team():
|
|
"""Sample team data for testing."""
|
|
return {
|
|
"id": 1,
|
|
"abbrev": "TST",
|
|
"sname": "Test",
|
|
"lname": "Test Team",
|
|
"gm_id": 12345,
|
|
"gmname": "Test GM",
|
|
"gsheet": "None",
|
|
"season": 4,
|
|
"wallet": 1000,
|
|
"color": "a6ce39",
|
|
"logo": "https://example.com/logo.png",
|
|
"ranking": 85,
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_cardset():
|
|
"""Sample cardset data for testing."""
|
|
return {
|
|
"id": 1,
|
|
"name": "MLB 2024",
|
|
"description": "Major League Baseball 2024 season cards",
|
|
"active": True,
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_paperdex():
|
|
"""Sample paperdex data for testing."""
|
|
return {
|
|
"id": 1,
|
|
"team_id": 1,
|
|
"cardset": "MLB 2024",
|
|
"total_cards": 100,
|
|
"unique_cards": 45,
|
|
"rarity_counts": {
|
|
"replacement": 20,
|
|
"reserve": 15,
|
|
"starter": 8,
|
|
"all-star": 2,
|
|
},
|
|
"team_counts": {"BOS": 5, "NYY": 4, "TB": 3},
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_game_data():
|
|
"""Sample game data for records/standings."""
|
|
return [
|
|
{
|
|
"home_score": 7,
|
|
"away_score": 4,
|
|
"home_team": {"abbrev": "BOS", "is_ai": True},
|
|
"away_team": {"abbrev": "TST", "is_ai": False},
|
|
"game_type": "minor-league",
|
|
"created_at": "2024-01-01T12:00:00Z",
|
|
},
|
|
{
|
|
"home_score": 3,
|
|
"away_score": 8,
|
|
"home_team": {"abbrev": "TST", "is_ai": False},
|
|
"away_team": {"abbrev": "NYY", "is_ai": True},
|
|
"game_type": "minor-league",
|
|
"created_at": "2024-01-02T15:00:00Z",
|
|
},
|
|
]
|
|
|
|
|
|
# Mock API calls
|
|
@pytest.fixture
|
|
def mock_db_get(monkeypatch):
|
|
"""Mock db_get function for API calls."""
|
|
|
|
async def mock_get(
|
|
endpoint, params=None, timeout=None, none_okay=False, object_id=None
|
|
):
|
|
if "players" in endpoint:
|
|
return {"count": 1, "players": [sample_player()]}
|
|
elif "teams" in endpoint:
|
|
return {"count": 1, "teams": [sample_team()]}
|
|
elif "cardsets" in endpoint:
|
|
return {"count": 1, "cardsets": [sample_cardset()]}
|
|
elif "paperdex" in endpoint:
|
|
return {"count": 1, "paperdex": [sample_paperdex()]}
|
|
else:
|
|
return {"count": 0}
|
|
|
|
mock_fn = AsyncMock(side_effect=mock_get)
|
|
monkeypatch.setattr("api_calls.db_get", mock_fn)
|
|
return mock_fn
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_db_post(monkeypatch):
|
|
"""Mock db_post function for API calls."""
|
|
|
|
async def mock_post(endpoint, payload=None, timeout=None):
|
|
return (
|
|
{"id": 1, "status": "success", **payload}
|
|
if payload
|
|
else {"id": 1, "status": "success"}
|
|
)
|
|
|
|
mock_fn = AsyncMock(side_effect=mock_post)
|
|
monkeypatch.setattr("api_calls.db_post", mock_fn)
|
|
return mock_fn
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_db_patch(monkeypatch):
|
|
"""Mock db_patch function for API calls."""
|
|
|
|
async def mock_patch(endpoint, object_id=None, params=None):
|
|
return {"id": object_id, "status": "updated"}
|
|
|
|
mock_fn = AsyncMock(side_effect=mock_patch)
|
|
monkeypatch.setattr("api_calls.db_patch", mock_fn)
|
|
return mock_fn
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_db_delete(monkeypatch):
|
|
"""Mock db_delete function for API calls."""
|
|
|
|
async def mock_delete(endpoint, object_id=None):
|
|
return {"id": object_id, "status": "deleted"}
|
|
|
|
mock_fn = AsyncMock(side_effect=mock_delete)
|
|
monkeypatch.setattr("api_calls.db_delete", mock_fn)
|
|
return mock_fn
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_helper_functions(monkeypatch):
|
|
"""Mock helper functions commonly used across modules."""
|
|
|
|
# Mock helper functions
|
|
monkeypatch.setattr("helpers.legal_channel", lambda ctx: True)
|
|
monkeypatch.setattr(
|
|
"helpers.get_team_by_owner", AsyncMock(return_value=sample_team())
|
|
)
|
|
monkeypatch.setattr(
|
|
"helpers.get_card_embeds", lambda player: [Mock(spec=discord.Embed)]
|
|
)
|
|
monkeypatch.setattr("helpers.embed_pagination", AsyncMock())
|
|
monkeypatch.setattr(
|
|
"helpers.get_team_embed", lambda title, team: Mock(spec=discord.Embed)
|
|
)
|
|
monkeypatch.setattr("search_utils.cardset_search", lambda query: ["MLB 2024"])
|
|
monkeypatch.setattr(
|
|
"search_utils.fuzzy_player_search", lambda query: ["Test Player"]
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_role():
|
|
"""Mock Discord role for permission testing."""
|
|
role = Mock(spec=discord.Role)
|
|
role.name = "Paper Dynasty Players"
|
|
return role
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_permissions():
|
|
"""Mock permission checks."""
|
|
|
|
def has_role_mock(*role_names):
|
|
async def decorator(func):
|
|
return func
|
|
|
|
return decorator
|
|
|
|
return has_role_mock
|
|
|
|
|
|
# Event loop fixture for async tests
|
|
@pytest.fixture(scope="session")
|
|
def event_loop():
|
|
"""Create an instance of the default event loop for the test session."""
|
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
yield loop
|
|
loop.close()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def setup_logging():
|
|
"""Setup logging for tests to avoid noise."""
|
|
import logging
|
|
|
|
logging.getLogger("discord_app").setLevel(logging.CRITICAL)
|