paper-dynasty-card-creation/tests/test_promo_description_protection.py
Cal Corum 0a17745389 Run black and ruff across entire codebase
Standardize formatting with black and apply ruff auto-fixes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 14:24:33 -05:00

367 lines
13 KiB
Python

"""
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 pandas as pd
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"