extends GutTest ## Unit tests for Player.gd var player: Player func before_each(): player = Player.new(0, "Test Player") ## Initialization Tests func test_initialization(): assert_eq(player.player_index, 0) assert_eq(player.player_name, "Test Player") assert_not_null(player.deck) assert_not_null(player.hand) assert_not_null(player.field_forwards) assert_not_null(player.field_backups) assert_not_null(player.damage_zone) assert_not_null(player.break_zone) assert_not_null(player.cp_pool) func test_default_name(): var player1 = Player.new(0) var player2 = Player.new(1) assert_eq(player1.player_name, "Player 1") assert_eq(player2.player_name, "Player 2") func test_zones_have_correct_owner(): assert_eq(player.deck.owner_index, 0) assert_eq(player.hand.owner_index, 0) assert_eq(player.field_forwards.owner_index, 0) func test_constants(): assert_eq(Player.MAX_HAND_SIZE, 5) assert_eq(Player.MAX_BACKUPS, 5) assert_eq(Player.DAMAGE_TO_LOSE, 7) ## Drawing Tests func test_draw_cards(): # Manually add cards to deck for i in range(10): var card = CardInstance.new(TestCardData.create_forward("c" + str(i), "Card " + str(i)), 0) player.deck.add_card(card) var drawn = player.draw_cards(5) assert_eq(drawn.size(), 5) assert_eq(player.hand.get_count(), 5) assert_eq(player.deck.get_count(), 5) func test_draw_from_empty_deck(): var drawn = player.draw_cards(3) assert_eq(drawn.size(), 0) assert_eq(player.hand.get_count(), 0) func test_draw_partial_deck(): for i in range(2): var card = CardInstance.new(TestCardData.create_forward("c" + str(i)), 0) player.deck.add_card(card) var drawn = player.draw_cards(5) # Try to draw 5, only 2 available assert_eq(drawn.size(), 2) assert_eq(player.hand.get_count(), 2) assert_eq(player.deck.get_count(), 0) func test_can_draw(): assert_false(player.can_draw()) player.deck.add_card(CardInstance.new(TestCardData.create_forward(), 0)) assert_true(player.can_draw()) ## CP Generation Tests func test_discard_for_cp(): var card = CardInstance.new(TestCardData.create_forward("test", "Test Card", Enums.Element.FIRE), 0) player.hand.add_card(card) var result = player.discard_for_cp(card) assert_true(result) assert_eq(player.hand.get_count(), 0) assert_eq(player.break_zone.get_count(), 1) assert_eq(player.cp_pool.get_cp(Enums.Element.FIRE), 2) func test_discard_for_cp_generates_correct_element(): var ice_card = CardInstance.new(TestCardData.create_forward("test", "Ice Card", Enums.Element.ICE), 0) player.hand.add_card(ice_card) player.discard_for_cp(ice_card) assert_eq(player.cp_pool.get_cp(Enums.Element.ICE), 2) assert_eq(player.cp_pool.get_cp(Enums.Element.FIRE), 0) func test_discard_light_card_for_cp_fails(): var card = CardInstance.new(TestCardData.create_light_forward(), 0) player.hand.add_card(card) var result = player.discard_for_cp(card) assert_false(result) assert_eq(player.hand.get_count(), 1) # Still in hand assert_eq(player.cp_pool.get_total_cp(), 0) func test_discard_dark_card_for_cp_fails(): var card = CardInstance.new(TestCardData.create_dark_forward(), 0) player.hand.add_card(card) var result = player.discard_for_cp(card) assert_false(result) assert_eq(player.hand.get_count(), 1) func test_discard_card_not_in_hand_fails(): var card = CardInstance.new(TestCardData.create_forward(), 0) # Don't add to hand var result = player.discard_for_cp(card) assert_false(result) func test_dull_backup_for_cp(): var backup = CardInstance.new(TestCardData.create_backup("test", "Test Backup", Enums.Element.ICE), 0) player.field_backups.add_card(backup) var result = player.dull_backup_for_cp(backup) assert_true(result) assert_true(backup.is_dull()) assert_eq(player.cp_pool.get_cp(Enums.Element.ICE), 1) func test_dull_already_dull_backup_fails(): var backup = CardInstance.new(TestCardData.create_backup(), 0) backup.dull() player.field_backups.add_card(backup) var result = player.dull_backup_for_cp(backup) assert_false(result) func test_dull_forward_for_cp_fails(): var forward = CardInstance.new(TestCardData.create_forward(), 0) player.field_backups.add_card(forward) # Incorrectly in backups zone var result = player.dull_backup_for_cp(forward) assert_false(result) # is_backup() check fails func test_dull_backup_not_on_field_fails(): var backup = CardInstance.new(TestCardData.create_backup(), 0) player.hand.add_card(backup) # In hand, not on field var result = player.dull_backup_for_cp(backup) assert_false(result) ## Card Play Tests - Forward func test_play_forward_card(): var card = CardInstance.new(TestCardData.create_forward("test", "Test Forward", Enums.Element.FIRE, 3), 0) player.hand.add_card(card) player.cp_pool.add_cp(Enums.Element.FIRE, 3) var spent = player.play_card(card) assert_false(spent.is_empty()) assert_eq(player.hand.get_count(), 0) assert_eq(player.field_forwards.get_count(), 1) assert_true(card.is_active()) func test_play_forward_calls_entered_field(): var card = CardInstance.new(TestCardData.create_forward("test", "Test Forward", Enums.Element.FIRE, 3), 0) card.turns_on_field = 5 # Artificially set player.hand.add_card(card) player.cp_pool.add_cp(Enums.Element.FIRE, 3) player.play_card(card) assert_eq(card.turns_on_field, 0) # Reset by entered_field ## Card Play Tests - Backup func test_play_backup_enters_dull(): var card = CardInstance.new(TestCardData.create_backup("test", "Test Backup", Enums.Element.EARTH, 2), 0) player.hand.add_card(card) player.cp_pool.add_cp(Enums.Element.EARTH, 2) player.play_card(card) assert_eq(player.field_backups.get_count(), 1) assert_true(card.is_dull()) # Backups enter dull func test_play_card_insufficient_cp(): var card = CardInstance.new(TestCardData.create_forward("test", "Test Forward", Enums.Element.FIRE, 3), 0) player.hand.add_card(card) player.cp_pool.add_cp(Enums.Element.FIRE, 1) # Not enough var spent = player.play_card(card) assert_true(spent.is_empty()) assert_eq(player.hand.get_count(), 1) # Still in hand assert_eq(player.field_forwards.get_count(), 0) func test_play_card_not_in_hand(): var card = CardInstance.new(TestCardData.create_forward("test", "Test Forward", Enums.Element.FIRE, 3), 0) # Don't add to hand player.cp_pool.add_cp(Enums.Element.FIRE, 5) var spent = player.play_card(card) assert_true(spent.is_empty()) ## Field Limit Tests func test_max_backups_limit(): # Fill backup field for i in range(5): var backup = CardInstance.new(TestCardData.create_backup("b" + str(i), "Backup " + str(i), Enums.Element.FIRE, 1, true), 0) player.field_backups.add_card(backup) # Try to play 6th backup var sixth_backup = CardInstance.new(TestCardData.create_backup("b5", "Backup 6", Enums.Element.FIRE, 1, true), 0) player.hand.add_card(sixth_backup) player.cp_pool.add_cp(Enums.Element.FIRE, 2) var spent = player.play_card(sixth_backup) assert_true(spent.is_empty()) assert_eq(player.field_backups.get_count(), 5) assert_eq(player.hand.get_count(), 1) # Still in hand ## Unique Name Restriction Tests func test_unique_name_restriction_forwards(): var cloud1 = CardInstance.new(TestCardData.create_forward("c1", "Cloud", Enums.Element.FIRE, 2, 5000, false), 0) player.field_forwards.add_card(cloud1) var cloud2 = CardInstance.new(TestCardData.create_forward("c2", "Cloud", Enums.Element.FIRE, 2, 5000, false), 0) player.hand.add_card(cloud2) player.cp_pool.add_cp(Enums.Element.FIRE, 3) var spent = player.play_card(cloud2) assert_true(spent.is_empty()) # Can't play same name func test_unique_name_restriction_backups(): var aerith1 = CardInstance.new(TestCardData.create_backup("a1", "Aerith", Enums.Element.EARTH, 2, false), 0) player.field_backups.add_card(aerith1) var aerith2 = CardInstance.new(TestCardData.create_backup("a2", "Aerith", Enums.Element.EARTH, 2, false), 0) player.hand.add_card(aerith2) player.cp_pool.add_cp(Enums.Element.EARTH, 3) var spent = player.play_card(aerith2) assert_true(spent.is_empty()) func test_unique_name_restriction_cross_zone(): # Cloud as forward var cloud_forward = CardInstance.new(TestCardData.create_forward("cf", "Cloud", Enums.Element.FIRE, 3, 5000, false), 0) player.field_forwards.add_card(cloud_forward) # Try to play Cloud as backup (same name) var cloud_backup = CardInstance.new(TestCardData.create_backup("cb", "Cloud", Enums.Element.FIRE, 2, false), 0) player.hand.add_card(cloud_backup) player.cp_pool.add_cp(Enums.Element.FIRE, 3) var spent = player.play_card(cloud_backup) assert_true(spent.is_empty()) func test_generic_cards_can_share_names(): var mog1 = CardInstance.new(TestCardData.create_forward("m1", "Moogle", Enums.Element.WIND, 1, 3000, true), 0) player.field_forwards.add_card(mog1) var mog2 = CardInstance.new(TestCardData.create_forward("m2", "Moogle", Enums.Element.WIND, 1, 3000, true), 0) player.hand.add_card(mog2) player.cp_pool.add_cp(Enums.Element.WIND, 2) var spent = player.play_card(mog2) assert_false(spent.is_empty()) # Generic cards allowed assert_eq(player.field_forwards.get_count(), 2) ## Light/Dark Restriction Tests func test_light_dark_restriction(): var light1 = CardInstance.new(TestCardData.create_light_forward("l1", "Light Forward 1", 3, 7000), 0) player.field_forwards.add_card(light1) var light2 = CardInstance.new(TestCardData.create_light_forward("l2", "Light Forward 2", 3, 7000), 0) player.hand.add_card(light2) player.cp_pool.add_cp(Enums.Element.FIRE, 5) var spent = player.play_card(light2) assert_true(spent.is_empty()) # Can't have two Light/Dark cards func test_light_dark_restriction_dark_after_light(): var light = CardInstance.new(TestCardData.create_light_forward("l", "Light Forward", 3, 7000), 0) player.field_forwards.add_card(light) var dark = CardInstance.new(TestCardData.create_dark_forward("d", "Dark Forward", 3, 7000), 0) player.hand.add_card(dark) player.cp_pool.add_cp(Enums.Element.FIRE, 5) var spent = player.play_card(dark) assert_true(spent.is_empty()) func test_light_dark_restriction_backup_zone(): var light_backup = CardInstance.new(TestCardData.create_backup("lb", "Light Backup", Enums.Element.LIGHT, 2), 0) player.field_backups.add_card(light_backup) var light_forward = CardInstance.new(TestCardData.create_light_forward("lf", "Light Forward", 3, 7000), 0) player.hand.add_card(light_forward) player.cp_pool.add_cp(Enums.Element.FIRE, 5) var spent = player.play_card(light_forward) assert_true(spent.is_empty()) # Light in backups blocks light forward ## Damage Tests func test_take_damage(): for i in range(10): var card = CardInstance.new(TestCardData.create_forward("d" + str(i)), 0) player.deck.add_card(card) var damage_cards = player.take_damage(3) assert_eq(damage_cards.size(), 3) assert_eq(player.damage_zone.get_count(), 3) assert_eq(player.deck.get_count(), 7) func test_take_damage_from_empty_deck(): var damage_cards = player.take_damage(3) assert_eq(damage_cards.size(), 0) assert_eq(player.damage_zone.get_count(), 0) func test_take_damage_partial_deck(): for i in range(2): var card = CardInstance.new(TestCardData.create_forward("d" + str(i)), 0) player.deck.add_card(card) var damage_cards = player.take_damage(5) # Try 5, only 2 in deck assert_eq(damage_cards.size(), 2) assert_eq(player.damage_zone.get_count(), 2) func test_has_lost(): for i in range(10): var card = CardInstance.new(TestCardData.create_forward("d" + str(i)), 0) player.deck.add_card(card) player.take_damage(6) assert_false(player.has_lost()) player.take_damage(1) assert_true(player.has_lost()) func test_get_damage_count(): for i in range(5): var card = CardInstance.new(TestCardData.create_forward("d" + str(i)), 0) player.deck.add_card(card) player.take_damage(3) assert_eq(player.get_damage_count(), 3) ## Break Card Tests func test_break_forward(): var card = CardInstance.new(TestCardData.create_forward(), 0) player.field_forwards.add_card(card) var result = player.break_card(card) assert_true(result) assert_eq(player.field_forwards.get_count(), 0) assert_eq(player.break_zone.get_count(), 1) func test_break_backup(): var card = CardInstance.new(TestCardData.create_backup(), 0) player.field_backups.add_card(card) var result = player.break_card(card) assert_true(result) assert_eq(player.field_backups.get_count(), 0) assert_eq(player.break_zone.get_count(), 1) func test_break_card_not_on_field(): var card = CardInstance.new(TestCardData.create_forward(), 0) player.hand.add_card(card) var result = player.break_card(card) assert_false(result) ## Turn Cleanup Tests func test_activate_all(): var forward = CardInstance.new(TestCardData.create_forward("f", "Forward"), 0) var backup = CardInstance.new(TestCardData.create_backup("b", "Backup"), 0) forward.dull() backup.dull() player.field_forwards.add_card(forward) player.field_backups.add_card(backup) player.activate_all() assert_true(forward.is_active()) assert_true(backup.is_active()) func test_discard_to_hand_limit(): # Add 8 cards to hand for i in range(8): var card = CardInstance.new(TestCardData.create_forward("h" + str(i)), 0) player.hand.add_card(card) var discarded = player.discard_to_hand_limit() assert_eq(discarded.size(), 3) assert_eq(player.hand.get_count(), 5) assert_eq(player.break_zone.get_count(), 3) func test_discard_to_hand_limit_already_under(): for i in range(3): var card = CardInstance.new(TestCardData.create_forward("h" + str(i)), 0) player.hand.add_card(card) var discarded = player.discard_to_hand_limit() assert_eq(discarded.size(), 0) assert_eq(player.hand.get_count(), 3) func test_end_turn_cleanup(): player.cp_pool.add_cp(Enums.Element.FIRE, 3) var forward = CardInstance.new(TestCardData.create_forward(), 0) forward.power_modifiers.append(1000) forward.damage_received = 2000 forward.attacked_this_turn = true player.field_forwards.add_card(forward) player.end_turn_cleanup() assert_eq(player.cp_pool.get_total_cp(), 0) assert_eq(forward.power_modifiers.size(), 0) assert_eq(forward.damage_received, 0) assert_false(forward.attacked_this_turn) func test_start_turn(): var forward = CardInstance.new(TestCardData.create_forward(), 0) forward.turns_on_field = 0 player.field_forwards.add_card(forward) player.start_turn() assert_eq(forward.turns_on_field, 1) ## Query Tests func test_get_all_field_cards(): var forward1 = CardInstance.new(TestCardData.create_forward("f1"), 0) var forward2 = CardInstance.new(TestCardData.create_forward("f2"), 0) var backup = CardInstance.new(TestCardData.create_backup("b"), 0) player.field_forwards.add_card(forward1) player.field_forwards.add_card(forward2) player.field_backups.add_card(backup) var all_cards = player.get_all_field_cards() assert_eq(all_cards.size(), 3) func test_get_attackable_forwards(): var can_attack = CardInstance.new(TestCardData.create_forward("a"), 0) can_attack.turns_on_field = 1 var cannot_attack_dull = CardInstance.new(TestCardData.create_forward("b"), 0) cannot_attack_dull.turns_on_field = 1 cannot_attack_dull.dull() var cannot_attack_sickness = CardInstance.new(TestCardData.create_forward("c"), 0) cannot_attack_sickness.turns_on_field = 0 player.field_forwards.add_card(can_attack) player.field_forwards.add_card(cannot_attack_dull) player.field_forwards.add_card(cannot_attack_sickness) var attackers = player.get_attackable_forwards() assert_eq(attackers.size(), 1) assert_eq(attackers[0], can_attack) func test_get_blockable_forwards(): var can_block = CardInstance.new(TestCardData.create_forward("a"), 0) var cannot_block_dull = CardInstance.new(TestCardData.create_forward("b"), 0) cannot_block_dull.dull() player.field_forwards.add_card(can_block) player.field_forwards.add_card(cannot_block_dull) var blockers = player.get_blockable_forwards() assert_eq(blockers.size(), 1) assert_eq(blockers[0], can_block) ## Summon Tests func test_cast_summon(): var summon = CardInstance.new(TestCardData.create_summon("s", "Test Summon", Enums.Element.FIRE, 2), 0) player.hand.add_card(summon) player.cp_pool.add_cp(Enums.Element.FIRE, 2) var cast = player.cast_summon(summon) assert_eq(cast, summon) assert_eq(player.hand.get_count(), 0) func test_cast_summon_insufficient_cp(): var summon = CardInstance.new(TestCardData.create_summon("s", "Test Summon", Enums.Element.FIRE, 2), 0) player.hand.add_card(summon) player.cp_pool.add_cp(Enums.Element.FIRE, 1) var cast = player.cast_summon(summon) assert_null(cast) assert_eq(player.hand.get_count(), 1) func test_cast_non_summon_fails(): var forward = CardInstance.new(TestCardData.create_forward(), 0) player.hand.add_card(forward) player.cp_pool.add_cp(Enums.Element.FIRE, 5) var cast = player.cast_summon(forward) assert_null(cast)