283 lines
7.8 KiB
Python
283 lines
7.8 KiB
Python
# Shared fixtures and mocks for players refactor tests
|
|
|
|
import pytest
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, MagicMock, 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."""
|
|
from unittest.mock import patch
|
|
|
|
# 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) |