""" Tests for promo card description protection. This test verifies that: 1. Promo cardsets only update descriptions for NEW cards (cost == NEW_PLAYER_COST) 2. Regular cardsets update descriptions for all cards (except potm cards) 3. Existing promo cards keep their original month descriptions """ import pytest import pandas as pd from unittest.mock import MagicMock, AsyncMock, patch from creation_helpers import should_update_player_description, NEW_PLAYER_COST class TestShouldUpdatePlayerDescription: """Test the extracted should_update_player_description function directly.""" def test_promo_new_player(self): """New promo players should have description updated.""" result = should_update_player_description( cardset_name="2024 Promos", player_cost=NEW_PLAYER_COST, current_description="", new_description="May" ) assert result is True def test_promo_existing_player(self): """Existing promo players should NOT have description updated.""" result = should_update_player_description( cardset_name="2024 Promos", player_cost=100, current_description="April", new_description="May" ) assert result is False def test_regular_outdated_description(self): """Regular cardsets should update outdated descriptions.""" result = should_update_player_description( cardset_name="2025 Season", player_cost=100, current_description="2024", new_description="2025" ) assert result is True def test_regular_potm_player(self): """PotM cards should never be updated.""" result = should_update_player_description( cardset_name="2025 Season", player_cost=100, current_description="April PotM", new_description="2025" ) assert result is False def test_case_insensitive_promo_detection(self): """Promo detection should be case-insensitive.""" for cardset_name in ["2024 Promos", "2024 PROMOS", "2024 promos", "2024 ProMos"]: result = should_update_player_description( cardset_name=cardset_name, player_cost=100, current_description="April", new_description="May" ) assert result is False, f"Should protect existing cards in '{cardset_name}'" def test_case_insensitive_potm_detection(self): """PotM detection should be case-insensitive.""" for description in ["April PotM", "April POTM", "april potm", "APRIL POTM"]: result = should_update_player_description( cardset_name="2025 Season", player_cost=100, current_description=description, new_description="2025" ) assert result is False, f"Should protect '{description}' cards" class TestPromoDescriptionProtection: """Test suite for verifying promo card description protection logic.""" def setup_method(self): """Setup test data for each test method.""" # Mock cardsets self.promo_cardset = {'id': 21, 'name': '2024 Promos'} self.regular_cardset = {'id': 20, 'name': '2024 Season'} # Player description for the current run self.player_desc = 'May' # Current month for promo run # Sample player data scenarios self.existing_promo_player = pd.Series({ 'player_id': 1001, 'description': 'April', # Previous month 'cost': 100, # Existing card 'rarity': 3, 'new_rarity_id': 3, 'mlbclub': 'Yankees', 'franchise': 'NYY' }) self.new_promo_player = pd.Series({ 'player_id': 1002, 'description': '', 'cost': 99999, # NEW card indicator 'rarity': 99, 'new_rarity_id': 3, 'total_OPS': 0.850, 'mlbclub': 'Yankees', 'franchise': 'NYY' }) self.regular_player_outdated = pd.Series({ 'player_id': 2001, 'description': '2023', # Old description 'cost': 100, 'rarity': 3, 'new_rarity_id': 3, 'mlbclub': 'Yankees', 'franchise': 'NYY' }) self.potm_player = pd.Series({ 'player_id': 3001, 'description': 'April PotM', 'cost': 100, 'rarity': 3, 'new_rarity_id': 3, 'mlbclub': 'Yankees', 'franchise': 'NYY' }) def test_promo_cardset_protects_existing_cards(self): """Test that existing promo cards keep their original descriptions.""" params = [] is_promo_cardset = 'promo' in self.promo_cardset['name'].lower() # Simulate the logic from batters/creation.py if is_promo_cardset: if self.existing_promo_player['cost'] == 99999: params = [('description', self.player_desc)] else: if self.existing_promo_player['description'] != self.player_desc and 'potm' not in self.existing_promo_player['description'].lower(): params = [('description', self.player_desc)] # Assert that NO description update is added assert ('description', self.player_desc) not in params assert len(params) == 0, "Existing promo cards should NOT have description updates" def test_promo_cardset_updates_new_cards(self): """Test that NEW promo cards get the current month description.""" params = [] is_promo_cardset = 'promo' in self.promo_cardset['name'].lower() # Simulate the logic from batters/creation.py if is_promo_cardset: if self.new_promo_player['cost'] == 99999: params = [('description', self.player_desc)] else: if self.new_promo_player['description'] != self.player_desc and 'potm' not in self.new_promo_player['description'].lower(): params = [('description', self.player_desc)] # Assert that description IS updated for new cards assert ('description', self.player_desc) in params assert len(params) == 1, "New promo cards SHOULD get description updates" def test_regular_cardset_updates_descriptions(self): """Test that regular cardsets update outdated descriptions.""" params = [] is_promo_cardset = 'promo' in self.regular_cardset['name'].lower() # Simulate the logic from batters/creation.py if is_promo_cardset: if self.regular_player_outdated['cost'] == 99999: params = [('description', self.player_desc)] else: if self.regular_player_outdated['description'] != self.player_desc and 'potm' not in self.regular_player_outdated['description'].lower(): params = [('description', self.player_desc)] # Assert that description IS updated assert ('description', self.player_desc) in params assert len(params) == 1, "Regular cardsets SHOULD update descriptions" def test_potm_cards_never_updated(self): """Test that PotM cards never get description updates (both cardset types).""" # Test with promo cardset params_promo = [] is_promo_cardset = 'promo' in self.promo_cardset['name'].lower() if is_promo_cardset: if self.potm_player['cost'] == 99999: params_promo = [('description', self.player_desc)] else: if self.potm_player['description'] != self.player_desc and 'potm' not in self.potm_player['description'].lower(): params_promo = [('description', self.player_desc)] # Test with regular cardset params_regular = [] is_promo_cardset = 'promo' in self.regular_cardset['name'].lower() if is_promo_cardset: if self.potm_player['cost'] == 99999: params_regular = [('description', self.player_desc)] else: if self.potm_player['description'] != self.player_desc and 'potm' not in self.potm_player['description'].lower(): params_regular = [('description', self.player_desc)] # Assert PotM cards are never updated in either cardset type assert len(params_promo) == 0, "PotM cards should NEVER be updated in promo cardsets" assert len(params_regular) == 0, "PotM cards should NEVER be updated in regular cardsets" def test_case_insensitive_promo_detection(self): """Test that promo detection is case-insensitive.""" test_cases = [ {'id': 1, 'name': '2024 Promos'}, {'id': 2, 'name': '2024 PROMOS'}, {'id': 3, 'name': '2024 promos'}, {'id': 4, 'name': '2024 ProMos'}, ] for cardset in test_cases: is_promo = 'promo' in cardset['name'].lower() assert is_promo == True, f"Should detect '{cardset['name']}' as promo cardset" def test_non_promo_cardsets_not_detected(self): """Test that non-promo cardsets are not incorrectly detected as promos.""" test_cases = [ {'id': 1, 'name': '2024 Season'}, {'id': 2, 'name': '2024 Live'}, {'id': 3, 'name': '1998 Replay'}, ] for cardset in test_cases: is_promo = 'promo' in cardset['name'].lower() assert is_promo == False, f"Should NOT detect '{cardset['name']}' as promo cardset" class TestPromoWorkflowScenario: """Integration-style tests simulating the real workflow.""" def test_monthly_promo_workflow(self): """ Simulate the real-world scenario: - April: Create cards with 'April' description - May: Run again, should NOT rename April cards to May """ promo_cardset = {'id': 21, 'name': '2024 Promos'} # Step 1: April run - create some cards april_desc = 'April' april_players = pd.DataFrame([ {'player_id': 1001, 'description': '', 'cost': 99999, 'rarity': 99, 'new_rarity_id': 3}, # New in April {'player_id': 1002, 'description': '', 'cost': 99999, 'rarity': 99, 'new_rarity_id': 2}, # New in April ]) # After April run, these would have description='April' april_players['description'] = april_desc april_players['cost'] = 100 # Simulate that they now have real costs # Step 2: May run - add new player, should not rename April players may_desc = 'May' may_players = pd.DataFrame([ {'player_id': 1001, 'description': 'April', 'cost': 100, 'rarity': 3, 'new_rarity_id': 3}, # Existing April card {'player_id': 1002, 'description': 'April', 'cost': 100, 'rarity': 2, 'new_rarity_id': 2}, # Existing April card {'player_id': 1003, 'description': '', 'cost': 99999, 'rarity': 99, 'new_rarity_id': 4}, # NEW May card ]) updates = {} for idx, player in may_players.iterrows(): params = [] is_promo_cardset = 'promo' in promo_cardset['name'].lower() if is_promo_cardset: if player['cost'] == 99999: params = [('description', may_desc)] else: if player['description'] != may_desc and 'potm' not in player['description'].lower(): params = [('description', may_desc)] if params: updates[player['player_id']] = params # Assertions assert 1001 not in updates, "Player 1001 (April card) should NOT be updated" assert 1002 not in updates, "Player 1002 (April card) should NOT be updated" assert 1003 in updates, "Player 1003 (NEW May card) SHOULD be updated" assert updates[1003] == [('description', 'May')], "New May card should get 'May' description"