paper-dynasty-discord/tests/test_api_calls.py
Cal Corum 3debfd6e82 Catchup commit
Includes discord_ui refactor, testing overhaul, addition of
2025-07-22 09:22:19 -05:00

164 lines
6.6 KiB
Python

import pytest
import aiohttp
from unittest.mock import Mock, patch, AsyncMock
from exceptions import DatabaseError
import api_calls
class TestUtilityFunctions:
"""Test utility functions in api_calls."""
def test_param_char_with_params(self):
"""Test param_char returns & when other_params is truthy."""
assert api_calls.param_char(True) == '&'
assert api_calls.param_char(['param1']) == '&'
assert api_calls.param_char({'key': 'value'}) == '&'
assert api_calls.param_char('some_param') == '&'
def test_param_char_without_params(self):
"""Test param_char returns ? when other_params is falsy."""
assert api_calls.param_char(False) == '?'
assert api_calls.param_char(None) == '?'
assert api_calls.param_char([]) == '?'
assert api_calls.param_char({}) == '?'
assert api_calls.param_char('') == '?'
assert api_calls.param_char(0) == '?'
@patch('api_calls.DB_URL', 'https://test.example.com/api')
def test_get_req_url_basic(self):
"""Test basic URL generation without object_id or params."""
result = api_calls.get_req_url('teams')
expected = 'https://test.example.com/api/v2/teams'
assert result == expected
@patch('api_calls.DB_URL', 'https://test.example.com/api')
def test_get_req_url_with_version(self):
"""Test URL generation with custom API version."""
result = api_calls.get_req_url('teams', api_ver=1)
expected = 'https://test.example.com/api/v1/teams'
assert result == expected
@patch('api_calls.DB_URL', 'https://test.example.com/api')
def test_get_req_url_with_object_id(self):
"""Test URL generation with object_id."""
result = api_calls.get_req_url('teams', object_id=123)
expected = 'https://test.example.com/api/v2/teams/123'
assert result == expected
@patch('api_calls.DB_URL', 'https://test.example.com/api')
def test_get_req_url_with_params(self):
"""Test URL generation with parameters."""
params = [('season', '7'), ('active', 'true')]
result = api_calls.get_req_url('teams', params=params)
expected = 'https://test.example.com/api/v2/teams?season=7&active=true'
assert result == expected
@patch('api_calls.DB_URL', 'https://test.example.com/api')
def test_get_req_url_complete(self):
"""Test URL generation with all parameters."""
params = [('season', '7'), ('limit', '10')]
result = api_calls.get_req_url('games', api_ver=1, object_id=456, params=params)
expected = 'https://test.example.com/api/v1/games/456?season=7&limit=10'
assert result == expected
@patch('api_calls.logger')
def test_log_return_value_short_string(self, mock_logger):
"""Test logging short return values."""
api_calls.log_return_value('Short log message')
mock_logger.info.assert_called_once_with('\n\nreturn: Short log message')
@patch('api_calls.logger')
def test_log_return_value_long_string(self, mock_logger):
"""Test logging long return values that get chunked."""
long_string = 'A' * 5000 # 5000 character string
api_calls.log_return_value(long_string)
# Should have been called twice (first chunk + second chunk)
assert mock_logger.info.call_count == 2
# First call should include the "return:" prefix
assert '\n\nreturn: ' in mock_logger.info.call_args_list[0][0][0]
@patch('api_calls.logger')
def test_log_return_value_extremely_long_string(self, mock_logger):
"""Test logging extremely long return values that get snipped."""
extremely_long_string = 'B' * 400000 # 400k character string (exceeds 300k limit)
api_calls.log_return_value(extremely_long_string)
# Should warn about snipping
mock_logger.warning.assert_called_with('[ S N I P P E D ]')
def test_team_hash(self):
"""Test team hash generation."""
mock_team = {
'sname': 'TestTeam',
'gmid': 1234567
}
result = api_calls.team_hash(mock_team)
# Expected format: last char + gmid/6950123 + second-to-last char + gmid/42069123
expected = f'm{1234567 / 6950123:.0f}a{1234567 / 42069123:.0f}'
assert result == expected
# Note: Async database function tests are complex due to aiohttp mocking
# For now, focusing on utility functions which provide significant coverage improvement
class TestSpecificFunctions:
"""Test specific API wrapper functions."""
@pytest.mark.asyncio
@patch('api_calls.db_get')
async def test_get_team_by_abbrev_found(self, mock_db_get):
"""Test get_team_by_abbrev function when team is found."""
mock_db_get.return_value = {
'count': 1,
'teams': [{'id': 123, 'abbrev': 'TEST', 'name': 'Test Team'}]
}
result = await api_calls.get_team_by_abbrev('TEST')
assert result == {'id': 123, 'abbrev': 'TEST', 'name': 'Test Team'}
mock_db_get.assert_called_once_with('teams', params=[('abbrev', 'TEST')])
@pytest.mark.asyncio
@patch('api_calls.db_get')
async def test_get_team_by_abbrev_not_found(self, mock_db_get):
"""Test get_team_by_abbrev function when team is not found."""
mock_db_get.return_value = {
'count': 0,
'teams': []
}
result = await api_calls.get_team_by_abbrev('NONEXISTENT')
assert result is None
mock_db_get.assert_called_once_with('teams', params=[('abbrev', 'NONEXISTENT')])
@pytest.mark.asyncio
@patch('api_calls.db_post')
async def test_post_to_dex(self, mock_db_post):
"""Test post_to_dex function."""
mock_db_post.return_value = {'id': 456, 'posted': True}
mock_player = {'id': 123}
mock_team = {'id': 456}
result = await api_calls.post_to_dex(mock_player, mock_team)
assert result == {'id': 456, 'posted': True}
mock_db_post.assert_called_once_with('paperdex', payload={'player_id': 123, 'team_id': 456})
class TestEnvironmentConfiguration:
"""Test environment-based configuration."""
def test_db_url_exists(self):
"""Test that DB_URL is configured."""
assert api_calls.DB_URL is not None
assert 'manticorum.com' in api_calls.DB_URL
def test_auth_token_exists(self):
"""Test that AUTH_TOKEN is configured."""
assert api_calls.AUTH_TOKEN is not None
assert 'Authorization' in api_calls.AUTH_TOKEN