Add comprehensive engine tests and fix action field name bugs

Bug fixes in engine.py:
- PlayPokemonAction: card_id -> card_instance_id
- PlayTrainerAction: card_id -> card_instance_id
- UseAbilityAction: pokemon_card_id -> pokemon_id
- SelectActiveAction: card_id -> pokemon_id
- record_ability_use() -> ability_uses_this_turn += 1

Added 26 new tests covering:
- Energy deck setup (Pokemon Pocket style)
- Prize card mode
- Deck size validation (too large)
- PlayPokemonAction (to active, to bench, not found)
- EvolvePokemonAction (success, not in hand, target not found)
- PlayTrainerAction (item, supporter, stadium, replacement)
- UseAbilityAction (success, not found, invalid index)
- SelectActiveAction (forced action, not on bench)
- Deck-out on turn start
- Attack edge cases (no energy, invalid index)
- Retreat without bench
- Attach energy from energy zone

Test count: 711 -> 737 (+26)
Coverage: 89% -> 94% overall, engine.py 55% -> 81%
This commit is contained in:
Cal Corum 2026-01-25 13:34:42 -06:00
parent 3f830b25b7
commit fe2e1091f9
2 changed files with 1089 additions and 17 deletions

View File

@ -450,7 +450,7 @@ class GameEngine:
action: PlayPokemonAction,
) -> ActionResult:
"""Execute playing a Basic Pokemon from hand to bench/active."""
card = player.hand.remove(action.card_id)
card = player.hand.remove(action.card_instance_id)
if not card:
return ActionResult(success=False, message="Card not in hand")
@ -462,7 +462,7 @@ class GameEngine:
success=True,
message="Played Pokemon to active",
state_changes=[
{"type": "play_pokemon", "zone": "active", "card_id": action.card_id}
{"type": "play_pokemon", "zone": "active", "card_id": action.card_instance_id}
],
)
@ -472,7 +472,9 @@ class GameEngine:
return ActionResult(
success=True,
message="Played Pokemon to bench",
state_changes=[{"type": "play_pokemon", "zone": "bench", "card_id": action.card_id}],
state_changes=[
{"type": "play_pokemon", "zone": "bench", "card_id": action.card_instance_id}
],
)
def _execute_evolve(
@ -585,7 +587,7 @@ class GameEngine:
action: PlayTrainerAction,
) -> ActionResult:
"""Execute playing a Trainer card."""
card = player.hand.remove(action.card_id)
card = player.hand.remove(action.card_instance_id)
if not card:
return ActionResult(success=False, message="Card not in hand")
@ -618,7 +620,7 @@ class GameEngine:
return ActionResult(
success=True,
message="Stadium played",
state_changes=[{"type": "play_stadium", "card_id": action.card_id}],
state_changes=[{"type": "play_stadium", "card_id": action.card_instance_id}],
)
elif card_def.trainer_type == TrainerType.ITEM:
player.items_played_this_turn += 1
@ -630,7 +632,7 @@ class GameEngine:
return ActionResult(
success=True,
message="Trainer card played",
state_changes=[{"type": "play_trainer", "card_id": action.card_id}],
state_changes=[{"type": "play_trainer", "card_id": action.card_instance_id}],
)
async def _execute_use_ability(
@ -642,10 +644,10 @@ class GameEngine:
"""Execute using a Pokemon's ability."""
# Find Pokemon with ability
pokemon = None
if action.pokemon_card_id in player.active:
pokemon = player.active.get(action.pokemon_card_id)
elif action.pokemon_card_id in player.bench:
pokemon = player.bench.get(action.pokemon_card_id)
if action.pokemon_id in player.active:
pokemon = player.active.get(action.pokemon_id)
elif action.pokemon_id in player.bench:
pokemon = player.bench.get(action.pokemon_id)
if not pokemon:
return ActionResult(success=False, message="Pokemon not found")
@ -659,15 +661,15 @@ class GameEngine:
ability = card_def.abilities[action.ability_index]
# Mark ability as used
pokemon.record_ability_use(action.ability_index)
# Mark ability as used (increment counter)
pokemon.ability_uses_this_turn += 1
# Execute ability effect (placeholder - would use effect system)
return ActionResult(
success=True,
message=f"Used ability: {ability.name}",
state_changes=[
{"type": "use_ability", "pokemon": action.pokemon_card_id, "ability": ability.name}
{"type": "use_ability", "pokemon": action.pokemon_id, "ability": ability.name}
],
)
@ -792,7 +794,7 @@ class GameEngine:
) -> ActionResult:
"""Execute selecting a new active Pokemon (forced action)."""
# Move selected Pokemon from bench to active
new_active = player.bench.remove(action.card_id)
new_active = player.bench.remove(action.pokemon_id)
if not new_active:
return ActionResult(success=False, message="Pokemon not found on bench")
@ -804,7 +806,7 @@ class GameEngine:
return ActionResult(
success=True,
message="New active Pokemon selected",
state_changes=[{"type": "select_active", "card_id": action.card_id}],
state_changes=[{"type": "select_active", "card_id": action.pokemon_id}],
)
def _execute_resign(

File diff suppressed because it is too large Load Diff