test runner added

This commit is contained in:
2026-01-28 11:22:20 -05:00
parent 8b5a7b1989
commit f4c7bab6b0
154 changed files with 18934 additions and 22 deletions

View File

@@ -0,0 +1,530 @@
extends GutTest
## Integration tests for GameState.gd
var game_state: GameState
# Signal tracking
var game_started_called: bool = false
var game_ended_called: bool = false
var card_played_called: bool = false
var damage_dealt_called: bool = false
var last_damage_player: int = -1
var last_damage_amount: int = 0
func before_each():
game_state = GameState.new()
_setup_test_game()
_connect_signals()
func _setup_test_game():
# Manually setup players without CardDatabase autoload
game_state.players.clear()
game_state.players.append(Player.new(0, "Player 1"))
game_state.players.append(Player.new(1, "Player 2"))
# Add cards directly to decks (50 cards each for full game)
for i in range(50):
var card1 = CardInstance.new(TestCardData.create_forward(
"p1-" + str(i), "Card " + str(i), Enums.Element.FIRE, 2 + (i % 4), 5000, true
), 0)
var card2 = CardInstance.new(TestCardData.create_forward(
"p2-" + str(i), "Card " + str(i), Enums.Element.ICE, 2 + (i % 4), 5000, true
), 1)
game_state.players[0].deck.add_card(card1)
game_state.players[1].deck.add_card(card2)
game_state.players[0].deck.shuffle()
game_state.players[1].deck.shuffle()
func _connect_signals():
game_started_called = false
game_ended_called = false
card_played_called = false
damage_dealt_called = false
game_state.game_started.connect(func(): game_started_called = true)
game_state.game_ended.connect(func(_winner): game_ended_called = true)
game_state.card_played.connect(func(_card, _player): card_played_called = true)
game_state.damage_dealt.connect(func(player, amount, _cards):
damage_dealt_called = true
last_damage_player = player
last_damage_amount = amount
)
## Initialization Tests
func test_initial_state():
assert_false(game_state.game_active)
assert_eq(game_state.winner_index, -1)
assert_eq(game_state.players.size(), 2)
assert_not_null(game_state.turn_manager)
## Game Start Tests
func test_start_game():
game_state.start_game(0)
assert_true(game_state.game_active)
assert_true(game_started_called)
assert_eq(game_state.turn_manager.current_player_index, 0)
# Player 0 has 5 (initial) + 1 (first turn draw) = 6
assert_eq(game_state.players[0].hand.get_count(), 6)
# Player 1 still has 5 (hasn't drawn yet)
assert_eq(game_state.players[1].hand.get_count(), 5)
func test_start_game_player_1_first():
game_state.start_game(1)
assert_eq(game_state.turn_manager.current_player_index, 1)
assert_true(game_state.players[1].is_first_player)
func test_start_game_auto_executes_phases():
game_state.start_game(0)
# start_game calls turn_manager.start_game(0)
# which emits phase_changed(ACTIVE)
# GameState._on_phase_changed executes ACTIVE phase and advances to DRAW
# Then executes DRAW phase and advances to MAIN_1
# After all that, we should be in MAIN_1
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.MAIN_1)
func test_first_turn_draws_one_card():
# Initial hands have 5 cards each
# On first turn, current player draws 1 more (first turn rule)
game_state.start_game(0)
# Player 0 drew 5 (initial) + 1 (first turn draw) = total 6 in hand? No wait...
# setup draws 5, then draw phase draws 1 more
# Actually, start_game calls draw_cards(5) for both, THEN starts turn which draws again
# Let me verify: draw_cards(5) then turn_manager.start_game triggers phase ACTIVE -> advance -> DRAW
# DRAW phase draws get_draw_count() = 1 (first turn)
assert_eq(game_state.players[0].hand.get_count(), 6) # 5 + 1
func test_subsequent_turn_draws_two():
game_state.start_game(0)
# Progress through player 0's turn to end
game_state.end_main_phase() # MAIN_1 -> ATTACK
game_state.end_attack_phase() # ATTACK -> MAIN_2
game_state.end_main_phase() # MAIN_2 -> END -> auto -> ACTIVE -> DRAW -> MAIN_1
# Now player 1's turn, they drew 2 cards
# Player 1 had 5 (initial) + 2 (normal draw) = 7
assert_eq(game_state.players[1].hand.get_count(), 7)
## Player Access Tests
func test_get_current_player():
game_state.start_game(0)
var current = game_state.get_current_player()
assert_eq(current, game_state.players[0])
func test_get_opponent():
game_state.start_game(0)
var opponent = game_state.get_opponent()
assert_eq(opponent, game_state.players[1])
func test_get_player():
assert_eq(game_state.get_player(0), game_state.players[0])
assert_eq(game_state.get_player(1), game_state.players[1])
assert_null(game_state.get_player(2))
assert_null(game_state.get_player(-1))
## Card Play Tests
func test_play_card_success():
game_state.start_game(0)
var player = game_state.get_current_player()
var card = player.hand.get_top_card()
player.cp_pool.add_cp(card.get_element(), card.card_data.cost)
var spent = game_state.play_card(0, card)
assert_false(spent.is_empty())
assert_true(card_played_called)
func test_play_card_wrong_phase():
game_state.start_game(0)
# Manually set phase to something other than main
game_state.turn_manager.current_phase = Enums.TurnPhase.DRAW
var player = game_state.get_current_player()
var card = player.hand.get_top_card()
player.cp_pool.add_cp(card.get_element(), 10)
var spent = game_state.play_card(0, card)
assert_true(spent.is_empty())
func test_play_card_wrong_player():
game_state.start_game(0) # Player 0's turn
var opponent = game_state.get_opponent()
var card = opponent.hand.get_top_card()
opponent.cp_pool.add_cp(card.get_element(), 10)
# Player 1 tries to play on player 0's turn
var spent = game_state.play_card(1, card)
assert_true(spent.is_empty())
func test_play_card_game_not_active():
# Don't start game
var player = game_state.players[0]
var card = CardInstance.new(TestCardData.create_forward(), 0)
player.hand.add_card(card)
player.cp_pool.add_cp(Enums.Element.FIRE, 5)
var spent = game_state.play_card(0, card)
assert_true(spent.is_empty())
## CP Generation Tests
func test_discard_for_cp():
game_state.start_game(0)
var player = game_state.get_current_player()
var card = player.hand.get_top_card()
var result = game_state.discard_for_cp(0, card)
assert_true(result)
assert_eq(player.cp_pool.get_total_cp(), 2)
func test_dull_backup_for_cp():
game_state.start_game(0)
var player = game_state.get_current_player()
var backup = CardInstance.new(TestCardData.create_backup("b", "Test Backup", Enums.Element.FIRE), 0)
player.field_backups.add_card(backup)
var result = game_state.dull_backup_for_cp(0, backup)
assert_true(result)
assert_eq(player.cp_pool.get_cp(Enums.Element.FIRE), 1)
## Turn Flow Tests
func test_full_turn_cycle():
game_state.start_game(0)
# After start_game, we're in MAIN_1
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.MAIN_1)
# End main phase 1
game_state.end_main_phase()
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.ATTACK)
# End attack phase (no attacks)
game_state.end_attack_phase()
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.MAIN_2)
# End main phase 2
game_state.end_main_phase()
# END phase auto-executes and advances to ACTIVE of next turn
# ACTIVE auto-executes and advances to DRAW
# DRAW auto-executes and advances to MAIN_1
# Should be player 1's turn now
assert_eq(game_state.turn_manager.current_player_index, 1)
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.MAIN_1)
## Combat Tests
func test_declare_attack():
game_state.start_game(0)
# Add a forward that can attack
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker", Enums.Element.FIRE, 3, 7000), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
# Get to attack phase
game_state.end_main_phase()
# Start attack declaration
var result = game_state.declare_attack(attacker)
assert_true(result)
assert_true(attacker.is_dull())
assert_true(attacker.attacked_this_turn)
assert_eq(game_state.turn_manager.current_attacker, attacker)
func test_declare_attack_with_brave():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_brave_forward(), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
assert_true(attacker.is_active()) # Brave doesn't dull when attacking
func test_declare_attack_invalid_card():
game_state.start_game(0)
var player = game_state.get_current_player()
var forward = CardInstance.new(TestCardData.create_forward(), 0)
forward.turns_on_field = 0 # Summoning sickness
player.field_forwards.add_card(forward)
game_state.end_main_phase()
var result = game_state.declare_attack(forward)
assert_false(result)
func test_declare_block():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker"), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
var opponent = game_state.get_opponent()
var blocker = CardInstance.new(TestCardData.create_forward("blk", "Blocker"), 1)
opponent.field_forwards.add_card(blocker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
var result = game_state.declare_block(blocker)
assert_true(result)
assert_eq(game_state.turn_manager.current_blocker, blocker)
func test_skip_block():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker"), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
var result = game_state.skip_block()
assert_true(result)
assert_null(game_state.turn_manager.current_blocker)
func test_unblocked_attack_deals_damage():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker"), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
game_state.skip_block()
game_state.resolve_combat()
assert_true(damage_dealt_called)
assert_eq(last_damage_player, 1) # Opponent takes damage
assert_eq(last_damage_amount, 1)
assert_eq(game_state.players[1].damage_zone.get_count(), 1)
func test_blocked_attack_combat():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker", Enums.Element.FIRE, 3, 7000, true), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
var opponent = game_state.get_opponent()
var blocker = CardInstance.new(TestCardData.create_forward("blk", "Blocker", Enums.Element.ICE, 3, 5000, true), 1)
opponent.field_forwards.add_card(blocker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
game_state.declare_block(blocker)
game_state.resolve_combat()
# Attacker 7000 vs Blocker 5000
# Blocker takes 7000 damage (>= 5000 power) -> broken
# Attacker takes 5000 damage (< 7000 power) -> survives
assert_eq(opponent.field_forwards.get_count(), 0) # Blocker broken
assert_eq(opponent.break_zone.get_count(), 1)
assert_eq(player.field_forwards.get_count(), 1) # Attacker survives
func test_both_forwards_break():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker", Enums.Element.FIRE, 3, 5000, true), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
var opponent = game_state.get_opponent()
var blocker = CardInstance.new(TestCardData.create_forward("blk", "Blocker", Enums.Element.ICE, 3, 5000, true), 1)
opponent.field_forwards.add_card(blocker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
game_state.declare_block(blocker)
game_state.resolve_combat()
# Both 5000 power, both take lethal damage
assert_eq(player.field_forwards.get_count(), 0)
assert_eq(opponent.field_forwards.get_count(), 0)
func test_multiple_attacks():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker1 = CardInstance.new(TestCardData.create_forward("a1", "Attacker 1", Enums.Element.FIRE, 2, 5000, true), 0)
var attacker2 = CardInstance.new(TestCardData.create_forward("a2", "Attacker 2", Enums.Element.FIRE, 2, 5000, true), 0)
attacker1.turns_on_field = 1
attacker2.turns_on_field = 1
player.field_forwards.add_card(attacker1)
player.field_forwards.add_card(attacker2)
game_state.end_main_phase()
# First attack
game_state.declare_attack(attacker1)
game_state.skip_block()
game_state.resolve_combat()
# Second attack
game_state.declare_attack(attacker2)
game_state.skip_block()
game_state.resolve_combat()
assert_eq(game_state.players[1].damage_zone.get_count(), 2)
## Win Condition Tests
func test_seven_damage_wins():
game_state.start_game(0)
# Add 7 attackers for player 0 (all can attack on same turn)
var player = game_state.players[0]
var attackers: Array[CardInstance] = []
for i in range(7):
var attacker = CardInstance.new(TestCardData.create_forward("a" + str(i), "Attacker", Enums.Element.FIRE, 2, 5000, true), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
attackers.append(attacker)
# Go to attack phase
game_state.end_main_phase()
# Attack 7 times with different forwards
for i in range(7):
if not game_state.game_active:
break
game_state.declare_attack(attackers[i])
game_state.skip_block()
game_state.resolve_combat()
assert_true(game_ended_called)
assert_false(game_state.game_active)
assert_eq(game_state.winner_index, 0) # Player 0 wins
## Edge Cases
func test_attack_phase_without_attacks():
game_state.start_game(0)
game_state.end_main_phase() # -> ATTACK
game_state.end_attack_phase() # -> MAIN_2
assert_eq(game_state.turn_manager.current_phase, Enums.TurnPhase.MAIN_2)
func test_declare_attack_not_in_attack_phase():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
# Still in MAIN_1
var result = game_state.declare_attack(attacker)
assert_false(result)
func test_declare_attack_card_not_on_field():
game_state.start_game(0)
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
attacker.turns_on_field = 1
# Don't add to field
game_state.end_main_phase()
var result = game_state.declare_attack(attacker)
assert_false(result)
func test_block_with_dull_card_fails():
game_state.start_game(0)
var player = game_state.get_current_player()
var attacker = CardInstance.new(TestCardData.create_forward("att", "Attacker"), 0)
attacker.turns_on_field = 1
player.field_forwards.add_card(attacker)
var opponent = game_state.get_opponent()
var blocker = CardInstance.new(TestCardData.create_forward("blk", "Blocker"), 1)
blocker.dull()
opponent.field_forwards.add_card(blocker)
game_state.end_main_phase()
game_state.declare_attack(attacker)
var result = game_state.declare_block(blocker)
assert_false(result)