test runner added
This commit is contained in:
530
tests/integration/test_game_state.gd
Normal file
530
tests/integration/test_game_state.gd
Normal 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)
|
||||
Reference in New Issue
Block a user