test runner added
This commit is contained in:
422
tests/unit/test_card_instance.gd
Normal file
422
tests/unit/test_card_instance.gd
Normal file
@@ -0,0 +1,422 @@
|
||||
extends GutTest
|
||||
|
||||
## Unit tests for CardInstance.gd
|
||||
|
||||
|
||||
## Initialization Tests
|
||||
|
||||
func test_initialization():
|
||||
var card_data = TestCardData.create_forward("test-id", "Test Card", Enums.Element.FIRE, 3, 5000)
|
||||
var card = CardInstance.new(card_data, 0)
|
||||
|
||||
assert_eq(card.card_data, card_data)
|
||||
assert_eq(card.owner_index, 0)
|
||||
assert_eq(card.controller_index, 0)
|
||||
assert_eq(card.current_power, 5000)
|
||||
assert_eq(card.state, Enums.CardState.ACTIVE)
|
||||
assert_eq(card.damage_received, 0)
|
||||
assert_eq(card.turns_on_field, 0)
|
||||
assert_false(card.attacked_this_turn)
|
||||
|
||||
|
||||
func test_initialization_with_null_data():
|
||||
var card = CardInstance.new(null, 0)
|
||||
|
||||
assert_null(card.card_data)
|
||||
assert_eq(card.current_power, 0)
|
||||
|
||||
|
||||
func test_unique_instance_ids():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var card3 = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_ne(card1.instance_id, card2.instance_id)
|
||||
assert_ne(card2.instance_id, card3.instance_id)
|
||||
assert_ne(card1.instance_id, card3.instance_id)
|
||||
|
||||
|
||||
func test_controller_defaults_to_owner():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 1)
|
||||
|
||||
assert_eq(card.owner_index, 1)
|
||||
assert_eq(card.controller_index, 1)
|
||||
|
||||
|
||||
## Card Type Checks
|
||||
|
||||
func test_is_forward():
|
||||
var forward = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var backup = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
var summon = CardInstance.new(TestCardData.create_summon(), 0)
|
||||
|
||||
assert_true(forward.is_forward())
|
||||
assert_false(backup.is_forward())
|
||||
assert_false(summon.is_forward())
|
||||
|
||||
|
||||
func test_is_backup():
|
||||
var forward = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var backup = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
var summon = CardInstance.new(TestCardData.create_summon(), 0)
|
||||
|
||||
assert_false(forward.is_backup())
|
||||
assert_true(backup.is_backup())
|
||||
assert_false(summon.is_backup())
|
||||
|
||||
|
||||
func test_is_summon():
|
||||
var forward = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var backup = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
var summon = CardInstance.new(TestCardData.create_summon(), 0)
|
||||
|
||||
assert_false(forward.is_summon())
|
||||
assert_false(backup.is_summon())
|
||||
assert_true(summon.is_summon())
|
||||
|
||||
|
||||
func test_type_check_with_null_data():
|
||||
var card = CardInstance.new(null, 0)
|
||||
|
||||
assert_false(card.is_forward())
|
||||
assert_false(card.is_backup())
|
||||
assert_false(card.is_summon())
|
||||
|
||||
|
||||
## State Management
|
||||
|
||||
func test_initial_state_is_active():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_true(card.is_active())
|
||||
assert_false(card.is_dull())
|
||||
|
||||
|
||||
func test_dull():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
card.dull()
|
||||
|
||||
assert_true(card.is_dull())
|
||||
assert_false(card.is_active())
|
||||
|
||||
|
||||
func test_activate():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.dull()
|
||||
|
||||
card.activate()
|
||||
|
||||
assert_true(card.is_active())
|
||||
assert_false(card.is_dull())
|
||||
|
||||
|
||||
## Power Tests
|
||||
|
||||
func test_get_power_base():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
assert_eq(card.get_power(), 5000)
|
||||
|
||||
|
||||
func test_get_power_with_positive_modifier():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
card.power_modifiers.append(1000)
|
||||
|
||||
assert_eq(card.get_power(), 6000)
|
||||
|
||||
|
||||
func test_get_power_with_multiple_modifiers():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
card.power_modifiers.append(1000)
|
||||
card.power_modifiers.append(2000)
|
||||
card.power_modifiers.append(-500)
|
||||
|
||||
assert_eq(card.get_power(), 7500)
|
||||
|
||||
|
||||
func test_get_power_with_negative_modifier():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
card.power_modifiers.append(-2000)
|
||||
|
||||
assert_eq(card.get_power(), 3000)
|
||||
|
||||
|
||||
func test_get_power_floors_at_zero():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
card.power_modifiers.append(-10000)
|
||||
|
||||
assert_eq(card.get_power(), 0)
|
||||
|
||||
|
||||
## Attack Eligibility Tests
|
||||
|
||||
func test_can_attack_basic():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 1 # Been on field for a turn
|
||||
|
||||
assert_true(card.can_attack())
|
||||
|
||||
|
||||
func test_cannot_attack_if_dull():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 1
|
||||
card.dull()
|
||||
|
||||
assert_false(card.can_attack())
|
||||
|
||||
|
||||
func test_cannot_attack_if_already_attacked():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 1
|
||||
card.attacked_this_turn = true
|
||||
|
||||
assert_false(card.can_attack())
|
||||
|
||||
|
||||
func test_cannot_attack_summoning_sickness():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 0 # Just entered field
|
||||
|
||||
assert_false(card.can_attack())
|
||||
|
||||
|
||||
func test_can_attack_with_haste_on_first_turn():
|
||||
var card = CardInstance.new(TestCardData.create_haste_forward(), 0)
|
||||
card.turns_on_field = 0 # Just entered field
|
||||
|
||||
assert_true(card.has_haste())
|
||||
assert_true(card.can_attack())
|
||||
|
||||
|
||||
func test_backup_cannot_attack():
|
||||
var card = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
card.turns_on_field = 1
|
||||
|
||||
assert_false(card.can_attack())
|
||||
|
||||
|
||||
func test_summon_cannot_attack():
|
||||
var card = CardInstance.new(TestCardData.create_summon(), 0)
|
||||
card.turns_on_field = 1
|
||||
|
||||
assert_false(card.can_attack())
|
||||
|
||||
|
||||
## Block Eligibility Tests
|
||||
|
||||
func test_can_block_basic():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_true(card.can_block())
|
||||
|
||||
|
||||
func test_cannot_block_if_dull():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.dull()
|
||||
|
||||
assert_false(card.can_block())
|
||||
|
||||
|
||||
func test_backup_cannot_block():
|
||||
var card = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
|
||||
assert_false(card.can_block())
|
||||
|
||||
|
||||
func test_can_block_even_on_first_turn():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 0 # Just entered field
|
||||
|
||||
# Blocking doesn't have summoning sickness
|
||||
assert_true(card.can_block())
|
||||
|
||||
|
||||
## Ability Detection Tests
|
||||
|
||||
func test_has_haste():
|
||||
var haste_card = CardInstance.new(TestCardData.create_haste_forward(), 0)
|
||||
var normal_card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_true(haste_card.has_haste())
|
||||
assert_false(normal_card.has_haste())
|
||||
|
||||
|
||||
func test_has_brave():
|
||||
var brave_card = CardInstance.new(TestCardData.create_brave_forward(), 0)
|
||||
var normal_card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_true(brave_card.has_brave())
|
||||
assert_false(normal_card.has_brave())
|
||||
|
||||
|
||||
func test_has_first_strike():
|
||||
var first_strike_card = CardInstance.new(TestCardData.create_first_strike_forward(), 0)
|
||||
var normal_card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
assert_true(first_strike_card.has_first_strike())
|
||||
assert_false(normal_card.has_first_strike())
|
||||
|
||||
|
||||
func test_ability_checks_with_null_data():
|
||||
var card = CardInstance.new(null, 0)
|
||||
|
||||
assert_false(card.has_haste())
|
||||
assert_false(card.has_brave())
|
||||
assert_false(card.has_first_strike())
|
||||
|
||||
|
||||
## Element Tests
|
||||
|
||||
func test_get_element():
|
||||
var fire_card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE), 0)
|
||||
var ice_card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.ICE), 0)
|
||||
|
||||
assert_eq(fire_card.get_element(), Enums.Element.FIRE)
|
||||
assert_eq(ice_card.get_element(), Enums.Element.ICE)
|
||||
|
||||
|
||||
func test_get_elements():
|
||||
var elements: Array[Enums.Element] = [Enums.Element.FIRE, Enums.Element.ICE]
|
||||
var multi_card = CardInstance.new(TestCardData.create_multi_element_forward("id", "Multi", elements), 0)
|
||||
|
||||
var card_elements = multi_card.get_elements()
|
||||
|
||||
assert_eq(card_elements.size(), 2)
|
||||
assert_true(Enums.Element.FIRE in card_elements)
|
||||
assert_true(Enums.Element.ICE in card_elements)
|
||||
|
||||
|
||||
func test_is_light_or_dark():
|
||||
var fire_card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var light_card = CardInstance.new(TestCardData.create_light_forward(), 0)
|
||||
var dark_card = CardInstance.new(TestCardData.create_dark_forward(), 0)
|
||||
|
||||
assert_false(fire_card.is_light_or_dark())
|
||||
assert_true(light_card.is_light_or_dark())
|
||||
assert_true(dark_card.is_light_or_dark())
|
||||
|
||||
|
||||
## Damage Tests
|
||||
|
||||
func test_apply_damage():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
var broken = card.apply_damage(3000)
|
||||
|
||||
assert_false(broken)
|
||||
assert_eq(card.damage_received, 3000)
|
||||
|
||||
|
||||
func test_apply_damage_breaks_card():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
var broken = card.apply_damage(5000) # Damage equals power
|
||||
|
||||
assert_true(broken)
|
||||
|
||||
|
||||
func test_apply_damage_accumulates():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
|
||||
card.apply_damage(3000)
|
||||
var broken = card.apply_damage(2000) # Total 5000 = power
|
||||
|
||||
assert_true(broken)
|
||||
assert_eq(card.damage_received, 5000)
|
||||
|
||||
|
||||
func test_apply_damage_to_backup_fails():
|
||||
var card = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
|
||||
var broken = card.apply_damage(1000)
|
||||
|
||||
assert_false(broken) # Backups can't receive combat damage
|
||||
|
||||
|
||||
func test_apply_damage_considers_modifiers():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000), 0)
|
||||
card.power_modifiers.append(2000) # Power is now 7000
|
||||
|
||||
var broken = card.apply_damage(5000) # 5000 < 7000
|
||||
|
||||
assert_false(broken)
|
||||
|
||||
|
||||
## Lifecycle Tests
|
||||
|
||||
func test_entered_field():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 5
|
||||
card.attacked_this_turn = true
|
||||
card.damage_received = 1000
|
||||
|
||||
card.entered_field()
|
||||
|
||||
assert_eq(card.turns_on_field, 0)
|
||||
assert_false(card.attacked_this_turn)
|
||||
assert_eq(card.damage_received, 0)
|
||||
|
||||
|
||||
func test_start_turn():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.turns_on_field = 0
|
||||
|
||||
card.start_turn()
|
||||
|
||||
assert_eq(card.turns_on_field, 1)
|
||||
|
||||
|
||||
func test_end_turn_cleanup():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.power_modifiers.append(1000)
|
||||
card.power_modifiers.append(-500)
|
||||
card.damage_received = 2000
|
||||
card.attacked_this_turn = true
|
||||
|
||||
card.end_turn_cleanup()
|
||||
|
||||
assert_eq(card.power_modifiers.size(), 0)
|
||||
assert_eq(card.damage_received, 0)
|
||||
assert_false(card.attacked_this_turn)
|
||||
|
||||
|
||||
## Display Tests
|
||||
|
||||
func test_get_display_name():
|
||||
var card = CardInstance.new(TestCardData.create_forward("id", "Cloud"), 0)
|
||||
|
||||
assert_eq(card.get_display_name(), "Cloud")
|
||||
|
||||
|
||||
func test_get_display_name_null_data():
|
||||
var card = CardInstance.new(null, 0)
|
||||
|
||||
assert_eq(card.get_display_name(), "Unknown Card")
|
||||
|
||||
|
||||
## Dull Ability Tests
|
||||
|
||||
func test_can_use_dull_ability():
|
||||
var card = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
card.turns_on_field = 1
|
||||
|
||||
assert_true(card.can_use_dull_ability())
|
||||
|
||||
|
||||
func test_cannot_use_dull_ability_summoning_sickness():
|
||||
var card = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
card.turns_on_field = 0
|
||||
|
||||
assert_false(card.can_use_dull_ability())
|
||||
|
||||
|
||||
func test_can_use_dull_ability_with_haste():
|
||||
var card = CardInstance.new(TestCardData.create_haste_forward(), 0)
|
||||
card.turns_on_field = 0
|
||||
|
||||
assert_true(card.can_use_dull_ability())
|
||||
372
tests/unit/test_cppool.gd
Normal file
372
tests/unit/test_cppool.gd
Normal file
@@ -0,0 +1,372 @@
|
||||
extends GutTest
|
||||
|
||||
## Unit tests for CPPool.gd
|
||||
|
||||
var cp_pool: CPPool
|
||||
|
||||
|
||||
func before_each():
|
||||
cp_pool = CPPool.new()
|
||||
|
||||
|
||||
## Initialization Tests
|
||||
|
||||
func test_initial_state_empty():
|
||||
assert_eq(cp_pool.get_total_cp(), 0)
|
||||
for element in Enums.Element.values():
|
||||
assert_eq(cp_pool.get_cp(element), 0)
|
||||
|
||||
|
||||
## Basic CP Operations
|
||||
|
||||
func test_add_cp():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 2)
|
||||
assert_eq(cp_pool.get_total_cp(), 2)
|
||||
|
||||
|
||||
func test_add_cp_multiple_elements():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 3)
|
||||
cp_pool.add_cp(Enums.Element.WIND, 1)
|
||||
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 2)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.ICE), 3)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.WIND), 1)
|
||||
assert_eq(cp_pool.get_total_cp(), 6)
|
||||
|
||||
|
||||
func test_add_cp_accumulates():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 3)
|
||||
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 5)
|
||||
|
||||
|
||||
func test_add_cp_floors_at_zero():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, -5) # Try to go negative
|
||||
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 0)
|
||||
|
||||
|
||||
func test_clear_resets_all():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 3)
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 1)
|
||||
|
||||
cp_pool.clear()
|
||||
|
||||
assert_eq(cp_pool.get_total_cp(), 0)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 0)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.ICE), 0)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.LIGHT), 0)
|
||||
|
||||
|
||||
## Light/Dark CP Tests
|
||||
|
||||
func test_get_non_light_dark_cp():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 3)
|
||||
cp_pool.add_cp(Enums.Element.DARK, 1)
|
||||
|
||||
assert_eq(cp_pool.get_non_light_dark_cp(), 2)
|
||||
assert_eq(cp_pool.get_total_cp(), 6)
|
||||
|
||||
|
||||
func test_get_non_light_dark_cp_no_regular():
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 3)
|
||||
cp_pool.add_cp(Enums.Element.DARK, 2)
|
||||
|
||||
assert_eq(cp_pool.get_non_light_dark_cp(), 0)
|
||||
|
||||
|
||||
## Single Element Card Affordability Tests
|
||||
|
||||
func test_can_afford_single_element_card_with_exact_element():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
|
||||
# Have exactly 3 Fire CP
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 3)
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_can_afford_single_element_card_with_mixed_cp():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
|
||||
# Have 1 Fire + 2 Ice = enough total with required element
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2)
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_single_element_without_matching_element():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
|
||||
# Have plenty of CP but no Fire
|
||||
cp_pool.add_cp(Enums.Element.ICE, 5)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_single_element_insufficient_total():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
|
||||
# Have Fire but not enough total
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 1)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
## Multi-Element Card Affordability Tests
|
||||
|
||||
func test_can_afford_multi_element_card():
|
||||
var elements: Array[Enums.Element] = [Enums.Element.FIRE, Enums.Element.ICE]
|
||||
var card = TestCardData.create_multi_element_forward("id", "Multi", elements, 4, 7000)
|
||||
|
||||
# Have 1 Fire + 1 Ice + 2 Wind = enough with both required elements
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 1)
|
||||
cp_pool.add_cp(Enums.Element.WIND, 2)
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_multi_element_missing_one_element():
|
||||
var elements: Array[Enums.Element] = [Enums.Element.FIRE, Enums.Element.ICE]
|
||||
var card = TestCardData.create_multi_element_forward("id", "Multi", elements, 4, 7000)
|
||||
|
||||
# Have only Fire, missing Ice
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 4)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_multi_element_insufficient_total():
|
||||
var elements: Array[Enums.Element] = [Enums.Element.FIRE, Enums.Element.ICE]
|
||||
var card = TestCardData.create_multi_element_forward("id", "Multi", elements, 4, 7000)
|
||||
|
||||
# Have both elements but not enough total
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 1)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
## Light Card Affordability Tests
|
||||
|
||||
func test_can_afford_light_card():
|
||||
var card = TestCardData.create_light_forward("id", "Light Forward", 5, 9000)
|
||||
|
||||
# Light cards need at least 1 non-Light/Dark CP
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 4)
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_light_card_with_only_light_dark_cp():
|
||||
var card = TestCardData.create_light_forward("id", "Light Forward", 5, 9000)
|
||||
|
||||
# Only Light/Dark CP - not valid
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 5)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_light_card_insufficient_total():
|
||||
var card = TestCardData.create_light_forward("id", "Light Forward", 5, 9000)
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
## Dark Card Affordability Tests
|
||||
|
||||
func test_can_afford_dark_card():
|
||||
var card = TestCardData.create_dark_forward("id", "Dark Forward", 4, 8000)
|
||||
|
||||
# Dark cards also need at least 1 non-Light/Dark CP
|
||||
cp_pool.add_cp(Enums.Element.WATER, 1)
|
||||
cp_pool.add_cp(Enums.Element.DARK, 3)
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_cannot_afford_dark_card_with_only_light_dark_cp():
|
||||
var card = TestCardData.create_dark_forward("id", "Dark Forward", 4, 8000)
|
||||
|
||||
cp_pool.add_cp(Enums.Element.DARK, 10)
|
||||
|
||||
assert_false(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
## CP Spending Tests
|
||||
|
||||
func test_spend_for_card_single_element():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2)
|
||||
|
||||
var spent = cp_pool.spend_for_card(card)
|
||||
|
||||
assert_false(spent.is_empty())
|
||||
assert_eq(cp_pool.get_total_cp(), 1) # 4 - 3 = 1
|
||||
assert_true(Enums.Element.FIRE in spent) # Must have spent at least 1 Fire
|
||||
|
||||
|
||||
func test_spend_for_card_returns_empty_if_cannot_afford():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 3, 5000)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2) # No Fire
|
||||
|
||||
var spent = cp_pool.spend_for_card(card)
|
||||
|
||||
assert_true(spent.is_empty())
|
||||
assert_eq(cp_pool.get_total_cp(), 2) # No CP should be spent
|
||||
|
||||
|
||||
func test_spend_for_card_multi_element():
|
||||
var elements: Array[Enums.Element] = [Enums.Element.FIRE, Enums.Element.ICE]
|
||||
var card = TestCardData.create_multi_element_forward("id", "Multi", elements, 4, 7000)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2)
|
||||
cp_pool.add_cp(Enums.Element.WIND, 1)
|
||||
|
||||
var spent = cp_pool.spend_for_card(card)
|
||||
|
||||
assert_false(spent.is_empty())
|
||||
assert_eq(cp_pool.get_total_cp(), 1) # 5 - 4 = 1
|
||||
assert_true(Enums.Element.FIRE in spent)
|
||||
assert_true(Enums.Element.ICE in spent)
|
||||
|
||||
|
||||
func test_spend_for_card_light():
|
||||
var card = TestCardData.create_light_forward("id", "Light Forward", 3, 7000)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 3)
|
||||
|
||||
var spent = cp_pool.spend_for_card(card)
|
||||
|
||||
assert_false(spent.is_empty())
|
||||
assert_eq(cp_pool.get_total_cp(), 1) # 4 - 3 = 1
|
||||
|
||||
|
||||
func test_spend_for_card_prefers_non_light_dark():
|
||||
var card = TestCardData.create_forward("id", "Test", Enums.Element.FIRE, 2, 5000)
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.LIGHT, 2)
|
||||
|
||||
var spent = cp_pool.spend_for_card(card)
|
||||
|
||||
assert_false(spent.is_empty())
|
||||
# Should prefer spending Fire over Light
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.LIGHT), 2) # Light should be untouched
|
||||
|
||||
|
||||
## Ability Cost Tests
|
||||
|
||||
func test_can_afford_ability_no_cost():
|
||||
assert_true(cp_pool.can_afford_ability(null))
|
||||
|
||||
|
||||
func test_can_afford_ability_with_element_requirements():
|
||||
var cost = CardDatabase.CostData.new()
|
||||
cost.fire = 2
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
|
||||
assert_true(cp_pool.can_afford_ability(cost))
|
||||
|
||||
|
||||
func test_cannot_afford_ability_insufficient_element():
|
||||
var cost = CardDatabase.CostData.new()
|
||||
cost.fire = 2
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
|
||||
assert_false(cp_pool.can_afford_ability(cost))
|
||||
|
||||
|
||||
func test_can_afford_ability_with_generic():
|
||||
var cost = CardDatabase.CostData.new()
|
||||
cost.fire = 1
|
||||
cost.generic = 2
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 2)
|
||||
|
||||
assert_true(cp_pool.can_afford_ability(cost))
|
||||
|
||||
|
||||
func test_spend_for_ability():
|
||||
var cost = CardDatabase.CostData.new()
|
||||
cost.fire = 1
|
||||
cost.generic = 1
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 1)
|
||||
|
||||
var result = cp_pool.spend_for_ability(cost)
|
||||
|
||||
assert_true(result)
|
||||
# Spent 1 Fire (required) + 1 generic (from Fire or Ice)
|
||||
assert_eq(cp_pool.get_total_cp(), 1)
|
||||
|
||||
|
||||
func test_spend_for_ability_fails_if_cannot_afford():
|
||||
var cost = CardDatabase.CostData.new()
|
||||
cost.fire = 3
|
||||
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
|
||||
var result = cp_pool.spend_for_ability(cost)
|
||||
|
||||
assert_false(result)
|
||||
assert_eq(cp_pool.get_cp(Enums.Element.FIRE), 1) # No CP spent
|
||||
|
||||
|
||||
## Edge Cases
|
||||
|
||||
func test_can_afford_null_card():
|
||||
assert_false(cp_pool.can_afford_card(null))
|
||||
|
||||
|
||||
func test_spend_for_null_card():
|
||||
var spent = cp_pool.spend_for_card(null)
|
||||
assert_true(spent.is_empty())
|
||||
|
||||
|
||||
func test_zero_cost_card():
|
||||
var card = TestCardData.create_forward("id", "Free Card", Enums.Element.FIRE, 0, 3000)
|
||||
|
||||
# Zero cost still needs at least 1 of the element
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 1)
|
||||
|
||||
# Actually, checking the code: cost is 0, so get_total_cp() >= 0 is always true
|
||||
# But need 1 Fire for single element check
|
||||
# Let me verify this is correct behavior - a 0 cost card needs element CP
|
||||
# Actually no - if cost is 0, we still check get_total_cp() >= cost which is 0 >= 0
|
||||
# So we'd need 1 Fire (element check) but 0 total (cost check)
|
||||
# This might be a bug in the game logic - should test current behavior
|
||||
|
||||
assert_true(cp_pool.can_afford_card(card))
|
||||
|
||||
|
||||
func test_display_data():
|
||||
cp_pool.add_cp(Enums.Element.FIRE, 2)
|
||||
cp_pool.add_cp(Enums.Element.ICE, 0) # Zero should not appear
|
||||
cp_pool.add_cp(Enums.Element.WIND, 1)
|
||||
|
||||
var display = cp_pool.get_display_data()
|
||||
|
||||
assert_true("Fire" in display)
|
||||
assert_eq(display["Fire"], 2)
|
||||
assert_true("Wind" in display)
|
||||
assert_eq(display["Wind"], 1)
|
||||
assert_false("Ice" in display) # Zero values excluded
|
||||
596
tests/unit/test_player.gd
Normal file
596
tests/unit/test_player.gd
Normal file
@@ -0,0 +1,596 @@
|
||||
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)
|
||||
416
tests/unit/test_turn_manager.gd
Normal file
416
tests/unit/test_turn_manager.gd
Normal file
@@ -0,0 +1,416 @@
|
||||
extends GutTest
|
||||
|
||||
## Unit tests for TurnManager.gd
|
||||
|
||||
var turn_manager: TurnManager
|
||||
|
||||
# Signal tracking
|
||||
var phase_changed_called: bool = false
|
||||
var last_phase: Enums.TurnPhase
|
||||
var turn_changed_called: bool = false
|
||||
var last_turn_player: int = -1
|
||||
var turn_started_called: bool = false
|
||||
var turn_ended_called: bool = false
|
||||
|
||||
|
||||
func before_each():
|
||||
turn_manager = TurnManager.new()
|
||||
phase_changed_called = false
|
||||
turn_changed_called = false
|
||||
turn_started_called = false
|
||||
turn_ended_called = false
|
||||
|
||||
turn_manager.phase_changed.connect(_on_phase_changed)
|
||||
turn_manager.turn_changed.connect(_on_turn_changed)
|
||||
turn_manager.turn_started.connect(_on_turn_started)
|
||||
turn_manager.turn_ended.connect(_on_turn_ended)
|
||||
|
||||
|
||||
func _on_phase_changed(phase: Enums.TurnPhase):
|
||||
phase_changed_called = true
|
||||
last_phase = phase
|
||||
|
||||
|
||||
func _on_turn_changed(player_index: int):
|
||||
turn_changed_called = true
|
||||
last_turn_player = player_index
|
||||
|
||||
|
||||
func _on_turn_started(_player_index: int, _turn_number: int):
|
||||
turn_started_called = true
|
||||
|
||||
|
||||
func _on_turn_ended(_player_index: int):
|
||||
turn_ended_called = true
|
||||
|
||||
|
||||
## Initialization Tests
|
||||
|
||||
func test_initial_state():
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.ACTIVE)
|
||||
assert_eq(turn_manager.current_player_index, 0)
|
||||
assert_eq(turn_manager.turn_number, 0)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.PREPARATION)
|
||||
assert_null(turn_manager.current_attacker)
|
||||
assert_null(turn_manager.current_blocker)
|
||||
|
||||
|
||||
## Start Game Tests
|
||||
|
||||
func test_start_game_player_0():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_eq(turn_manager.turn_number, 1)
|
||||
assert_eq(turn_manager.current_player_index, 0)
|
||||
assert_true(turn_manager.is_first_turn)
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.ACTIVE)
|
||||
assert_true(phase_changed_called)
|
||||
assert_true(turn_started_called)
|
||||
|
||||
|
||||
func test_start_game_player_1():
|
||||
turn_manager.start_game(1)
|
||||
|
||||
assert_eq(turn_manager.current_player_index, 1)
|
||||
assert_eq(turn_manager.turn_number, 1)
|
||||
|
||||
|
||||
## Phase Progression Tests
|
||||
|
||||
func test_phase_progression_sequence():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
# ACTIVE -> DRAW
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.DRAW)
|
||||
|
||||
# DRAW -> MAIN_1
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.MAIN_1)
|
||||
|
||||
# MAIN_1 -> ATTACK
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.ATTACK)
|
||||
|
||||
# ATTACK -> MAIN_2
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.MAIN_2)
|
||||
|
||||
# MAIN_2 -> END
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.END)
|
||||
|
||||
|
||||
func test_phase_progression_wraps_to_new_turn():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
# Progress through all phases
|
||||
for i in range(5): # ACTIVE -> DRAW -> MAIN_1 -> ATTACK -> MAIN_2
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.END)
|
||||
|
||||
# END -> ACTIVE (new turn, player switches)
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.ACTIVE)
|
||||
assert_eq(turn_manager.current_player_index, 1) # Player switched
|
||||
assert_eq(turn_manager.turn_number, 2)
|
||||
assert_false(turn_manager.is_first_turn)
|
||||
|
||||
|
||||
func test_phase_emits_signal():
|
||||
turn_manager.start_game(0)
|
||||
phase_changed_called = false
|
||||
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_true(phase_changed_called)
|
||||
assert_eq(last_phase, Enums.TurnPhase.DRAW)
|
||||
|
||||
|
||||
func test_turn_changed_signal():
|
||||
turn_manager.start_game(0)
|
||||
turn_changed_called = false
|
||||
|
||||
# Progress through full turn
|
||||
for i in range(6):
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_true(turn_changed_called)
|
||||
assert_eq(last_turn_player, 1)
|
||||
|
||||
|
||||
func test_turn_ended_signal():
|
||||
turn_manager.start_game(0)
|
||||
turn_ended_called = false
|
||||
|
||||
# Progress through full turn
|
||||
for i in range(6):
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_true(turn_ended_called)
|
||||
|
||||
|
||||
## Phase Query Tests
|
||||
|
||||
func test_is_main_phase():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_false(turn_manager.is_main_phase()) # ACTIVE
|
||||
|
||||
turn_manager.advance_phase() # DRAW
|
||||
assert_false(turn_manager.is_main_phase())
|
||||
|
||||
turn_manager.advance_phase() # MAIN_1
|
||||
assert_true(turn_manager.is_main_phase())
|
||||
|
||||
turn_manager.advance_phase() # ATTACK
|
||||
assert_false(turn_manager.is_main_phase())
|
||||
|
||||
turn_manager.advance_phase() # MAIN_2
|
||||
assert_true(turn_manager.is_main_phase())
|
||||
|
||||
turn_manager.advance_phase() # END
|
||||
assert_false(turn_manager.is_main_phase())
|
||||
|
||||
|
||||
func test_is_attack_phase():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_false(turn_manager.is_attack_phase())
|
||||
|
||||
# Progress to attack phase
|
||||
turn_manager.advance_phase() # DRAW
|
||||
turn_manager.advance_phase() # MAIN_1
|
||||
turn_manager.advance_phase() # ATTACK
|
||||
|
||||
assert_true(turn_manager.is_attack_phase())
|
||||
|
||||
turn_manager.advance_phase() # MAIN_2
|
||||
assert_false(turn_manager.is_attack_phase())
|
||||
|
||||
|
||||
## Draw Count Tests
|
||||
|
||||
func test_first_turn_draws_one():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_eq(turn_manager.get_draw_count(), 1)
|
||||
|
||||
|
||||
func test_subsequent_turns_draw_two():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
# Complete first turn
|
||||
for i in range(6):
|
||||
turn_manager.advance_phase()
|
||||
|
||||
assert_false(turn_manager.is_first_turn)
|
||||
assert_eq(turn_manager.get_draw_count(), 2)
|
||||
|
||||
|
||||
## Attack Phase State Machine Tests
|
||||
|
||||
func test_attack_phase_initial_state():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.PREPARATION)
|
||||
assert_null(turn_manager.current_attacker)
|
||||
assert_null(turn_manager.current_blocker)
|
||||
|
||||
|
||||
func test_start_attack_declaration():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
var result = turn_manager.start_attack_declaration()
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.DECLARATION)
|
||||
|
||||
|
||||
func test_start_attack_declaration_invalid_state():
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration() # Now in DECLARATION
|
||||
|
||||
# Can't start again from DECLARATION
|
||||
var result = turn_manager.start_attack_declaration()
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
func test_set_attacker():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
|
||||
var result = turn_manager.set_attacker(attacker)
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(turn_manager.current_attacker, attacker)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.BLOCK_DECLARATION)
|
||||
|
||||
|
||||
func test_set_attacker_null_fails():
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
|
||||
var result = turn_manager.set_attacker(null)
|
||||
|
||||
assert_false(result)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.DECLARATION)
|
||||
|
||||
|
||||
func test_set_attacker_wrong_state_fails():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
turn_manager.start_game(0)
|
||||
# Don't call start_attack_declaration, still in PREPARATION
|
||||
|
||||
var result = turn_manager.set_attacker(attacker)
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
func test_set_blocker():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward("att"), 0)
|
||||
var blocker = CardInstance.new(TestCardData.create_forward("blk"), 1)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
turn_manager.set_attacker(attacker)
|
||||
|
||||
var result = turn_manager.set_blocker(blocker)
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(turn_manager.current_blocker, blocker)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.DAMAGE_RESOLUTION)
|
||||
|
||||
|
||||
func test_set_blocker_null_valid():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
turn_manager.set_attacker(attacker)
|
||||
|
||||
var result = turn_manager.set_blocker(null) # No block
|
||||
|
||||
assert_true(result)
|
||||
assert_null(turn_manager.current_blocker)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.DAMAGE_RESOLUTION)
|
||||
|
||||
|
||||
func test_set_blocker_wrong_state_fails():
|
||||
var blocker = CardInstance.new(TestCardData.create_forward(), 1)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
# Don't set attacker, still in DECLARATION
|
||||
|
||||
var result = turn_manager.set_blocker(blocker)
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
func test_complete_attack():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
turn_manager.set_attacker(attacker)
|
||||
turn_manager.set_blocker(null)
|
||||
|
||||
var result = turn_manager.complete_attack()
|
||||
|
||||
assert_true(result)
|
||||
assert_null(turn_manager.current_attacker)
|
||||
assert_null(turn_manager.current_blocker)
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.DECLARATION) # Ready for next attack
|
||||
|
||||
|
||||
func test_complete_attack_wrong_state_fails():
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
# Still in DECLARATION, not DAMAGE_RESOLUTION
|
||||
|
||||
var result = turn_manager.complete_attack()
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
func test_end_attack_phase_from_preparation():
|
||||
turn_manager.start_game(0)
|
||||
# Advance to attack phase
|
||||
turn_manager.advance_phase() # DRAW
|
||||
turn_manager.advance_phase() # MAIN_1
|
||||
turn_manager.advance_phase() # ATTACK
|
||||
|
||||
var result = turn_manager.end_attack_phase()
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.MAIN_2)
|
||||
|
||||
|
||||
func test_end_attack_phase_from_declaration():
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.advance_phase() # DRAW
|
||||
turn_manager.advance_phase() # MAIN_1
|
||||
turn_manager.advance_phase() # ATTACK
|
||||
turn_manager.start_attack_declaration()
|
||||
|
||||
var result = turn_manager.end_attack_phase()
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(turn_manager.current_phase, Enums.TurnPhase.MAIN_2)
|
||||
|
||||
|
||||
func test_end_attack_phase_invalid_state():
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
turn_manager.set_attacker(CardInstance.new(TestCardData.create_forward(), 0))
|
||||
# Now in BLOCK_DECLARATION
|
||||
|
||||
var result = turn_manager.end_attack_phase()
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
func test_attack_state_reset_on_new_turn():
|
||||
var attacker = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
turn_manager.start_game(0)
|
||||
turn_manager.start_attack_declaration()
|
||||
turn_manager.set_attacker(attacker)
|
||||
|
||||
# Complete the turn
|
||||
for i in range(6):
|
||||
turn_manager.advance_phase()
|
||||
|
||||
# New turn should have reset attack state
|
||||
assert_eq(turn_manager.attack_step, Enums.AttackStep.PREPARATION)
|
||||
assert_null(turn_manager.current_attacker)
|
||||
assert_null(turn_manager.current_blocker)
|
||||
|
||||
|
||||
## Display String Tests
|
||||
|
||||
func test_get_phase_string():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_eq(turn_manager.get_phase_string(), "Active Phase")
|
||||
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.get_phase_string(), "Draw Phase")
|
||||
|
||||
turn_manager.advance_phase()
|
||||
assert_eq(turn_manager.get_phase_string(), "Main Phase 1")
|
||||
|
||||
|
||||
func test_get_attack_step_string():
|
||||
turn_manager.start_game(0)
|
||||
|
||||
assert_eq(turn_manager.get_attack_step_string(), "Preparation")
|
||||
|
||||
turn_manager.start_attack_declaration()
|
||||
assert_eq(turn_manager.get_attack_step_string(), "Declare Attacker")
|
||||
|
||||
turn_manager.set_attacker(CardInstance.new(TestCardData.create_forward(), 0))
|
||||
assert_eq(turn_manager.get_attack_step_string(), "Declare Blocker")
|
||||
|
||||
turn_manager.set_blocker(null)
|
||||
assert_eq(turn_manager.get_attack_step_string(), "Damage Resolution")
|
||||
349
tests/unit/test_zone.gd
Normal file
349
tests/unit/test_zone.gd
Normal file
@@ -0,0 +1,349 @@
|
||||
extends GutTest
|
||||
|
||||
## Unit tests for Zone.gd
|
||||
|
||||
var zone: Zone
|
||||
|
||||
|
||||
func before_each():
|
||||
zone = Zone.new(Enums.ZoneType.HAND, 0)
|
||||
|
||||
|
||||
## Initialization Tests
|
||||
|
||||
func test_zone_initializes_with_correct_type():
|
||||
assert_eq(zone.zone_type, Enums.ZoneType.HAND)
|
||||
assert_eq(zone.owner_index, 0)
|
||||
|
||||
|
||||
func test_zone_initializes_empty():
|
||||
assert_eq(zone.get_count(), 0)
|
||||
assert_true(zone.is_empty())
|
||||
|
||||
|
||||
func test_zone_default_owner_is_negative_one():
|
||||
var shared_zone = Zone.new(Enums.ZoneType.STACK)
|
||||
assert_eq(shared_zone.owner_index, -1)
|
||||
|
||||
|
||||
## Add Card Tests
|
||||
|
||||
func test_add_card_succeeds():
|
||||
var card_data = TestCardData.create_forward()
|
||||
var card = CardInstance.new(card_data, 0)
|
||||
|
||||
var result = zone.add_card(card)
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(zone.get_count(), 1)
|
||||
assert_eq(card.zone_type, Enums.ZoneType.HAND)
|
||||
|
||||
|
||||
func test_add_duplicate_card_fails():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
var result = zone.add_card(card)
|
||||
|
||||
assert_false(result)
|
||||
assert_eq(zone.get_count(), 1)
|
||||
|
||||
|
||||
func test_add_card_at_top_default():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1", "Card 1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2", "Card 2"), 0)
|
||||
|
||||
zone.add_card(card1)
|
||||
zone.add_card(card2) # Default is at_top = true
|
||||
|
||||
assert_eq(zone.get_top_card(), card2)
|
||||
assert_eq(zone.get_bottom_card(), card1)
|
||||
|
||||
|
||||
func test_add_card_at_bottom():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1", "Card 1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2", "Card 2"), 0)
|
||||
|
||||
zone.add_card(card1, true) # at top
|
||||
zone.add_card(card2, false) # at bottom
|
||||
|
||||
assert_eq(zone.get_top_card(), card1)
|
||||
assert_eq(zone.get_bottom_card(), card2)
|
||||
|
||||
|
||||
func test_add_card_updates_card_zone_type():
|
||||
var deck_zone = Zone.new(Enums.ZoneType.DECK, 0)
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
card.zone_type = Enums.ZoneType.HAND
|
||||
|
||||
deck_zone.add_card(card)
|
||||
|
||||
assert_eq(card.zone_type, Enums.ZoneType.DECK)
|
||||
|
||||
|
||||
## Remove Card Tests
|
||||
|
||||
func test_remove_card_succeeds():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
var result = zone.remove_card(card)
|
||||
|
||||
assert_true(result)
|
||||
assert_eq(zone.get_count(), 0)
|
||||
|
||||
|
||||
func test_remove_nonexistent_card_fails():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
|
||||
var result = zone.remove_card(card)
|
||||
|
||||
assert_false(result)
|
||||
|
||||
|
||||
## Query Tests
|
||||
|
||||
func test_get_cards_returns_copy():
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
var cards = zone.get_cards()
|
||||
cards.clear() # Modify the returned array
|
||||
|
||||
assert_eq(zone.get_count(), 1) # Original should be unchanged
|
||||
|
||||
|
||||
func test_has_card():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2"), 0)
|
||||
zone.add_card(card1)
|
||||
|
||||
assert_true(zone.has_card(card1))
|
||||
assert_false(zone.has_card(card2))
|
||||
|
||||
|
||||
func test_get_card_at():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2"), 0)
|
||||
zone.add_card(card1)
|
||||
zone.add_card(card2)
|
||||
|
||||
assert_eq(zone.get_card_at(0), card1)
|
||||
assert_eq(zone.get_card_at(1), card2)
|
||||
assert_null(zone.get_card_at(2))
|
||||
assert_null(zone.get_card_at(-1))
|
||||
|
||||
|
||||
## Deck Operations Tests
|
||||
|
||||
func test_pop_top_card():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2"), 0)
|
||||
zone.add_card(card1)
|
||||
zone.add_card(card2)
|
||||
|
||||
var popped = zone.pop_top_card()
|
||||
|
||||
assert_eq(popped, card2)
|
||||
assert_eq(zone.get_count(), 1)
|
||||
assert_eq(zone.get_top_card(), card1)
|
||||
|
||||
|
||||
func test_pop_top_card_empty_zone():
|
||||
var popped = zone.pop_top_card()
|
||||
|
||||
assert_null(popped)
|
||||
|
||||
|
||||
func test_get_top_card_empty_zone():
|
||||
assert_null(zone.get_top_card())
|
||||
|
||||
|
||||
func test_get_bottom_card_empty_zone():
|
||||
assert_null(zone.get_bottom_card())
|
||||
|
||||
|
||||
func test_shuffle():
|
||||
# Add 10 cards
|
||||
for i in range(10):
|
||||
var card = CardInstance.new(TestCardData.create_forward("c" + str(i), "Card " + str(i)), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
var original_order = zone.get_cards().duplicate()
|
||||
zone.shuffle()
|
||||
var shuffled_order = zone.get_cards()
|
||||
|
||||
# With 10 cards, probability of same order after shuffle is 1/10! = ~0.000028%
|
||||
var different = false
|
||||
for i in range(10):
|
||||
if original_order[i] != shuffled_order[i]:
|
||||
different = true
|
||||
break
|
||||
assert_true(different, "Shuffle should change card order (statistically)")
|
||||
|
||||
|
||||
func test_clear():
|
||||
for i in range(5):
|
||||
var card = CardInstance.new(TestCardData.create_forward("c" + str(i)), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
var removed = zone.clear()
|
||||
|
||||
assert_eq(removed.size(), 5)
|
||||
assert_eq(zone.get_count(), 0)
|
||||
assert_true(zone.is_empty())
|
||||
|
||||
|
||||
## Type Filtering Tests
|
||||
|
||||
func test_get_forwards():
|
||||
var forward = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var backup = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
var summon = CardInstance.new(TestCardData.create_summon(), 0)
|
||||
zone.add_card(forward)
|
||||
zone.add_card(backup)
|
||||
zone.add_card(summon)
|
||||
|
||||
var forwards = zone.get_forwards()
|
||||
|
||||
assert_eq(forwards.size(), 1)
|
||||
assert_eq(forwards[0], forward)
|
||||
|
||||
|
||||
func test_get_backups():
|
||||
var forward = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
var backup = CardInstance.new(TestCardData.create_backup(), 0)
|
||||
zone.add_card(forward)
|
||||
zone.add_card(backup)
|
||||
|
||||
var backups = zone.get_backups()
|
||||
|
||||
assert_eq(backups.size(), 1)
|
||||
assert_eq(backups[0], backup)
|
||||
|
||||
|
||||
## State Filtering Tests
|
||||
|
||||
func test_get_active_cards():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2"), 0)
|
||||
card2.dull()
|
||||
zone.add_card(card1)
|
||||
zone.add_card(card2)
|
||||
|
||||
var active = zone.get_active_cards()
|
||||
|
||||
assert_eq(active.size(), 1)
|
||||
assert_eq(active[0], card1)
|
||||
|
||||
|
||||
func test_get_dull_cards():
|
||||
var card1 = CardInstance.new(TestCardData.create_forward("c1"), 0)
|
||||
var card2 = CardInstance.new(TestCardData.create_forward("c2"), 0)
|
||||
card2.dull()
|
||||
zone.add_card(card1)
|
||||
zone.add_card(card2)
|
||||
|
||||
var dull = zone.get_dull_cards()
|
||||
|
||||
assert_eq(dull.size(), 1)
|
||||
assert_eq(dull[0], card2)
|
||||
|
||||
|
||||
## Search Tests
|
||||
|
||||
func test_find_cards_by_name():
|
||||
var cloud1 = CardInstance.new(TestCardData.create_forward("c1", "Cloud"), 0)
|
||||
var cloud2 = CardInstance.new(TestCardData.create_forward("c2", "Cloud"), 0)
|
||||
var tifa = CardInstance.new(TestCardData.create_forward("c3", "Tifa"), 0)
|
||||
zone.add_card(cloud1)
|
||||
zone.add_card(cloud2)
|
||||
zone.add_card(tifa)
|
||||
|
||||
var found = zone.find_cards_by_name("Cloud")
|
||||
|
||||
assert_eq(found.size(), 2)
|
||||
|
||||
|
||||
func test_find_cards_by_element():
|
||||
var fire_card = CardInstance.new(TestCardData.create_forward("c1", "Fire Card", Enums.Element.FIRE), 0)
|
||||
var ice_card = CardInstance.new(TestCardData.create_forward("c2", "Ice Card", Enums.Element.ICE), 0)
|
||||
zone.add_card(fire_card)
|
||||
zone.add_card(ice_card)
|
||||
|
||||
var fire_cards = zone.find_cards_by_element(Enums.Element.FIRE)
|
||||
|
||||
assert_eq(fire_cards.size(), 1)
|
||||
assert_eq(fire_cards[0], fire_card)
|
||||
|
||||
|
||||
func test_has_card_with_name():
|
||||
var card = CardInstance.new(TestCardData.create_forward("c1", "Cloud"), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
assert_true(zone.has_card_with_name("Cloud"))
|
||||
assert_false(zone.has_card_with_name("Sephiroth"))
|
||||
|
||||
|
||||
func test_has_light_or_dark_with_light():
|
||||
var fire_card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(fire_card)
|
||||
assert_false(zone.has_light_or_dark())
|
||||
|
||||
var light_card = CardInstance.new(TestCardData.create_light_forward(), 0)
|
||||
zone.add_card(light_card)
|
||||
assert_true(zone.has_light_or_dark())
|
||||
|
||||
|
||||
func test_has_light_or_dark_with_dark():
|
||||
var dark_card = CardInstance.new(TestCardData.create_dark_forward(), 0)
|
||||
zone.add_card(dark_card)
|
||||
|
||||
assert_true(zone.has_light_or_dark())
|
||||
|
||||
|
||||
## Callback Tests
|
||||
|
||||
func test_on_card_added_callback():
|
||||
# Use array to capture value since GDScript lambdas need reference types
|
||||
var result = [null]
|
||||
zone.on_card_added = func(c): result[0] = c
|
||||
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
|
||||
assert_eq(result[0], card)
|
||||
|
||||
|
||||
func test_on_card_removed_callback():
|
||||
var result = [null]
|
||||
zone.on_card_removed = func(c): result[0] = c
|
||||
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
zone.remove_card(card)
|
||||
|
||||
assert_eq(result[0], card)
|
||||
|
||||
|
||||
func test_pop_triggers_removed_callback():
|
||||
var result = [null]
|
||||
zone.on_card_removed = func(c): result[0] = c
|
||||
|
||||
var card = CardInstance.new(TestCardData.create_forward(), 0)
|
||||
zone.add_card(card)
|
||||
zone.pop_top_card()
|
||||
|
||||
assert_eq(result[0], card)
|
||||
|
||||
|
||||
func test_clear_triggers_removed_callbacks():
|
||||
var counter = [0]
|
||||
zone.on_card_removed = func(_card): counter[0] += 1
|
||||
|
||||
for i in range(3):
|
||||
zone.add_card(CardInstance.new(TestCardData.create_forward("c" + str(i)), 0))
|
||||
|
||||
zone.clear()
|
||||
|
||||
assert_eq(counter[0], 3)
|
||||
Reference in New Issue
Block a user