major-domo-v2/tests/test_models_transaction.py
Cal Corum 1dd930e4b3 CLAUDE: Complete dice command system with fielding mechanics
Implements comprehensive dice rolling system for gameplay:

## New Features
- `/roll` and `!roll` commands for XdY dice notation with multiple roll support
- `/ab` and `!atbat` commands for baseball at-bat dice shortcuts (1d6;2d6;1d20)
- `/fielding` and `!f` commands for Super Advanced fielding with full position charts

## Technical Implementation
- Complete dice command package in commands/dice/
- Full range and error charts for all 8 defensive positions (1B,2B,3B,SS,LF,RF,CF,C)
- Pre-populated position choices for user-friendly slash command interface
- Backwards compatibility with prefix commands (!roll, !r, !dice, !ab, !atbat, !f, !fielding, !saf)
- Type-safe implementation following "Raise or Return" pattern

## Testing & Quality
- 30 comprehensive tests with 100% pass rate
- Complete test coverage for all dice functionality, parsing, validation, and error handling
- Integration with bot.py command loading system
- Maintainable data structures replacing verbose original implementation

## User Experience
- Consistent embed formatting across all commands
- Detailed fielding results with range and error analysis
- Support for complex dice combinations and multiple roll formats
- Clear error messages for invalid inputs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 22:30:31 -05:00

343 lines
13 KiB
Python

"""
Tests for Transaction model
Validates transaction model creation, validation, and business logic.
"""
import pytest
import copy
from datetime import datetime
from models.transaction import Transaction, RosterValidation
from models.player import Player
from models.team import Team
class TestTransaction:
"""Test Transaction model functionality."""
def test_transaction_creation_from_minimal_api_data(self):
"""Test creating transaction from minimal API data."""
# Create minimal test data matching actual API structure
player_data = {
'id': 12472,
'name': 'Test Player',
'wara': 2.47,
'season': 12,
'pos_1': 'LF'
}
team_data = {
'id': 508,
'abbrev': 'NYD',
'sname': 'Diamonds',
'lname': 'New York Diamonds',
'season': 12
}
transaction_data = {
'id': 27787,
'week': 10,
'season': 12,
'moveid': 'Season-012-Week-10-19-13:04:41',
'player': player_data,
'oldteam': team_data.copy(),
'newteam': {**team_data, 'id': 499, 'abbrev': 'WV', 'sname': 'Black Bears', 'lname': 'West Virginia Black Bears'},
'cancelled': False,
'frozen': False
}
transaction = Transaction.from_api_data(transaction_data)
assert transaction.id == 27787
assert transaction.week == 10
assert transaction.season == 12
assert transaction.moveid == 'Season-012-Week-10-19-13:04:41'
assert transaction.player.name == 'Test Player'
assert transaction.oldteam.abbrev == 'NYD'
assert transaction.newteam.abbrev == 'WV'
assert transaction.cancelled is False
assert transaction.frozen is False
def test_transaction_creation_from_complete_api_data(self):
"""Test creating transaction from complete API data structure."""
complete_data = {
'id': 27787,
'week': 10,
'player': {
'id': 12472,
'name': 'Yordan Alvarez',
'wara': 2.47,
'image': 'https://example.com/image.png',
'image2': None,
'team': {
'id': 508,
'abbrev': 'NYD',
'sname': 'Diamonds',
'lname': 'New York Diamonds',
'season': 12
},
'season': 12,
'pitcher_injury': None,
'pos_1': 'LF',
'pos_2': None,
'last_game': None,
'il_return': None,
'demotion_week': 1,
'headshot': None,
'strat_code': 'Alvarez,Y',
'bbref_id': 'alvaryo01',
'injury_rating': '1p65'
},
'oldteam': {
'id': 508,
'abbrev': 'NYD',
'sname': 'Diamonds',
'lname': 'New York Diamonds',
'season': 12
},
'newteam': {
'id': 499,
'abbrev': 'WV',
'sname': 'Black Bears',
'lname': 'West Virginia Black Bears',
'season': 12
},
'season': 12,
'moveid': 'Season-012-Week-10-19-13:04:41',
'cancelled': False,
'frozen': False
}
transaction = Transaction.from_api_data(complete_data)
assert transaction.id == 27787
assert transaction.player.name == 'Yordan Alvarez'
assert transaction.player.wara == 2.47
assert transaction.player.bbref_id == 'alvaryo01'
assert transaction.oldteam.lname == 'New York Diamonds'
assert transaction.newteam.lname == 'West Virginia Black Bears'
def test_transaction_status_properties(self):
"""Test transaction status property logic."""
base_data = self._create_base_transaction_data()
# Test pending transaction (not frozen, not cancelled)
pending_data = {**base_data, 'cancelled': False, 'frozen': False}
pending_transaction = Transaction.from_api_data(pending_data)
assert pending_transaction.is_pending is True
assert pending_transaction.is_frozen is False
assert pending_transaction.is_cancelled is False
assert pending_transaction.status_text == 'Pending'
assert pending_transaction.status_emoji == ''
# Test frozen transaction
frozen_data = {**base_data, 'cancelled': False, 'frozen': True}
frozen_transaction = Transaction.from_api_data(frozen_data)
assert frozen_transaction.is_pending is False
assert frozen_transaction.is_frozen is True
assert frozen_transaction.is_cancelled is False
assert frozen_transaction.status_text == 'Frozen'
assert frozen_transaction.status_emoji == '❄️'
# Test cancelled transaction
cancelled_data = {**base_data, 'cancelled': True, 'frozen': False}
cancelled_transaction = Transaction.from_api_data(cancelled_data)
assert cancelled_transaction.is_pending is False
assert cancelled_transaction.is_frozen is False
assert cancelled_transaction.is_cancelled is True
assert cancelled_transaction.status_text == 'Cancelled'
assert cancelled_transaction.status_emoji == ''
def test_transaction_move_description(self):
"""Test move description generation."""
transaction_data = self._create_base_transaction_data()
transaction = Transaction.from_api_data(transaction_data)
expected_description = 'Test Player: NYD → WV'
assert transaction.move_description == expected_description
def test_transaction_string_representation(self):
"""Test transaction string representation."""
transaction_data = self._create_base_transaction_data()
transaction = Transaction.from_api_data(transaction_data)
expected_str = '📋 Week 10: Test Player: NYD → WV - ⏳ Pending'
assert str(transaction) == expected_str
def test_major_league_move_detection(self):
"""Test major league move detection logic."""
base_data = self._create_base_transaction_data()
# Test major league to major league (should be True)
ml_to_ml_data = copy.deepcopy(base_data)
ml_to_ml = Transaction.from_api_data(ml_to_ml_data)
assert ml_to_ml.is_major_league_move is True
# Test major league to minor league (should be True)
ml_to_minor_data = copy.deepcopy(base_data)
ml_to_minor_data['newteam']['abbrev'] = 'WVMiL'
ml_to_minor = Transaction.from_api_data(ml_to_minor_data)
assert ml_to_minor.is_major_league_move is True
# Test minor league to major league (should be True)
minor_to_ml_data = copy.deepcopy(base_data)
minor_to_ml_data['oldteam']['abbrev'] = 'NYDMiL'
minor_to_ml = Transaction.from_api_data(minor_to_ml_data)
assert minor_to_ml.is_major_league_move is True
# Test FA to major league (should be True)
fa_to_ml_data = copy.deepcopy(base_data)
fa_to_ml_data['oldteam']['abbrev'] = 'FA'
fa_to_ml = Transaction.from_api_data(fa_to_ml_data)
assert fa_to_ml.is_major_league_move is True
# Test major league to FA (should be True)
ml_to_fa_data = copy.deepcopy(base_data)
ml_to_fa_data['newteam']['abbrev'] = 'FA'
ml_to_fa = Transaction.from_api_data(ml_to_fa_data)
assert ml_to_fa.is_major_league_move is True
# Test minor league to minor league (should be False)
minor_to_minor_data = copy.deepcopy(base_data)
minor_to_minor_data['oldteam']['abbrev'] = 'NYDMiL'
minor_to_minor_data['newteam']['abbrev'] = 'WVMiL'
minor_to_minor = Transaction.from_api_data(minor_to_minor_data)
assert minor_to_minor.is_major_league_move is False
# Test FA to FA (should be False - shouldn't happen but test edge case)
fa_to_fa_data = copy.deepcopy(base_data)
fa_to_fa_data['oldteam']['abbrev'] = 'FA'
fa_to_fa_data['newteam']['abbrev'] = 'FA'
fa_to_fa = Transaction.from_api_data(fa_to_fa_data)
assert fa_to_fa.is_major_league_move is False
def test_transaction_validation_errors(self):
"""Test transaction model validation with invalid data."""
# Test missing required fields
with pytest.raises(Exception): # Pydantic validation error
Transaction.from_api_data({})
with pytest.raises(Exception): # Missing player
Transaction.from_api_data({
'id': 1,
'week': 10,
'season': 12,
'moveid': 'test'
})
def _create_base_transaction_data(self):
"""Create base transaction data for testing."""
return {
'id': 27787,
'week': 10,
'season': 12,
'moveid': 'Season-012-Week-10-19-13:04:41',
'player': {
'id': 12472,
'name': 'Test Player',
'wara': 2.47,
'season': 12,
'pos_1': 'LF'
},
'oldteam': {
'id': 508,
'abbrev': 'NYD',
'sname': 'Diamonds',
'lname': 'New York Diamonds',
'season': 12
},
'newteam': {
'id': 499,
'abbrev': 'WV',
'sname': 'Black Bears',
'lname': 'West Virginia Black Bears',
'season': 12
},
'cancelled': False,
'frozen': False
}
class TestRosterValidation:
"""Test RosterValidation model functionality."""
def test_roster_validation_creation(self):
"""Test creating roster validation instance."""
validation = RosterValidation(
is_legal=True,
total_players=25,
active_players=25,
il_players=0,
total_sWAR=125.5
)
assert validation.is_legal is True
assert validation.total_players == 25
assert validation.active_players == 25
assert validation.il_players == 0
assert validation.total_sWAR == 125.5
assert validation.has_issues is False
def test_roster_validation_with_errors(self):
"""Test roster validation with errors."""
validation = RosterValidation(
is_legal=False,
errors=['Too many players on roster', 'Invalid player position'],
warnings=['Low WARA total'],
total_players=30,
active_players=28,
il_players=2,
total_sWAR=95.2
)
assert validation.is_legal is False
assert len(validation.errors) == 2
assert len(validation.warnings) == 1
assert validation.has_issues is True
assert validation.status_emoji == ''
def test_roster_validation_with_warnings_only(self):
"""Test roster validation with warnings but no errors."""
validation = RosterValidation(
is_legal=True,
warnings=['Roster could use more depth'],
total_players=23,
active_players=23,
total_sWAR=110.0
)
assert validation.is_legal is True
assert len(validation.errors) == 0
assert len(validation.warnings) == 1
assert validation.has_issues is True
assert validation.status_emoji == '⚠️'
def test_roster_validation_perfect(self):
"""Test perfectly valid roster."""
validation = RosterValidation(
is_legal=True,
total_players=25,
active_players=25,
total_sWAR=130.0
)
assert validation.is_legal is True
assert len(validation.errors) == 0
assert len(validation.warnings) == 0
assert validation.has_issues is False
assert validation.status_emoji == ''
def test_roster_validation_defaults(self):
"""Test roster validation with default values."""
validation = RosterValidation(is_legal=True)
assert validation.total_players == 0
assert validation.active_players == 0
assert validation.il_players == 0
assert validation.minor_league_players == 0
assert validation.total_sWAR == 0.0
assert len(validation.errors) == 0
assert len(validation.warnings) == 0