extends GutTest ## Tests for ability cost validation in AbilitySystem # ============================================================================= # CP COST VALIDATION TESTS # ============================================================================= func test_validate_empty_cost_always_valid() -> void: var ability_system = AbilitySystem.new() var cost = {} var player = MockPlayer.new() var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Empty cost should always be valid") ability_system.free() func test_validate_cp_cost_with_sufficient_cp() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 3} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 5) var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Should be valid with sufficient CP") ability_system.free() func test_validate_cp_cost_with_insufficient_cp() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 5} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 3) var result = ability_system._validate_ability_cost(cost, null, player) assert_false(result.valid, "Should be invalid with insufficient CP") assert_true("Not enough CP" in result.reason, "Reason should mention CP") ability_system.free() func test_validate_specific_element_cp_cost_valid() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "element": "FIRE"} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 3) var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Should be valid with sufficient Fire CP") ability_system.free() func test_validate_specific_element_cp_cost_invalid() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "element": "FIRE"} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.ICE, 5) # Wrong element var result = ability_system._validate_ability_cost(cost, null, player) assert_false(result.valid, "Should be invalid with wrong element CP") assert_true("FIRE CP" in result.reason, "Reason should mention Fire") ability_system.free() func test_validate_any_element_cp_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 4, "element": "ANY"} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 2) player.cp_pool.add_cp(Enums.Element.ICE, 2) var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Should be valid with total CP from multiple elements") ability_system.free() # ============================================================================= # DISCARD COST VALIDATION TESTS # ============================================================================= func test_validate_discard_cost_with_sufficient_cards() -> void: var ability_system = AbilitySystem.new() var cost = {"discard": 2} var player = MockPlayer.new() # Add 3 cards to hand for i in range(3): var card = _create_mock_card() player.hand.add_card(card) var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Should be valid with sufficient cards to discard") ability_system.free() func test_validate_discard_cost_with_insufficient_cards() -> void: var ability_system = AbilitySystem.new() var cost = {"discard": 3} var player = MockPlayer.new() # Add only 1 card to hand player.hand.add_card(_create_mock_card()) var result = ability_system._validate_ability_cost(cost, null, player) assert_false(result.valid, "Should be invalid with insufficient cards") assert_true("discard" in result.reason, "Reason should mention discard") ability_system.free() # ============================================================================= # DULL SELF COST VALIDATION TESTS # ============================================================================= func test_validate_dull_self_cost_when_active() -> void: var ability_system = AbilitySystem.new() var cost = {"dull_self": true} var source = _create_mock_card() source.activate() # Ensure active var player = MockPlayer.new() var result = ability_system._validate_ability_cost(cost, source, player) assert_true(result.valid, "Should be valid when card is active") ability_system.free() func test_validate_dull_self_cost_when_already_dull() -> void: var ability_system = AbilitySystem.new() var cost = {"dull_self": true} var source = _create_mock_card() source.dull() # Already dull var player = MockPlayer.new() var result = ability_system._validate_ability_cost(cost, source, player) assert_false(result.valid, "Should be invalid when card is already dull") assert_true("dulled" in result.reason, "Reason should mention dulled") ability_system.free() # ============================================================================= # SPECIFIC DISCARD COST VALIDATION TESTS # ============================================================================= func test_validate_specific_discard_cost_with_matching_card() -> void: var ability_system = AbilitySystem.new() var cost = {"specific_discard": "Cloud"} var player = MockPlayer.new() var cloud = _create_mock_card_with_name("Cloud") player.hand.add_card(cloud) var result = ability_system._validate_ability_cost(cost, null, player) assert_true(result.valid, "Should be valid with matching card in hand") ability_system.free() func test_validate_specific_discard_cost_without_matching_card() -> void: var ability_system = AbilitySystem.new() var cost = {"specific_discard": "Cloud"} var player = MockPlayer.new() var sephiroth = _create_mock_card_with_name("Sephiroth") player.hand.add_card(sephiroth) var result = ability_system._validate_ability_cost(cost, null, player) assert_false(result.valid, "Should be invalid without matching card") assert_true("Cloud" in result.reason, "Reason should mention required card") ability_system.free() # ============================================================================= # COMBINED COST VALIDATION TESTS # ============================================================================= func test_validate_combined_cp_and_dull_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "dull_self": true} var source = _create_mock_card() source.activate() var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 3) var result = ability_system._validate_ability_cost(cost, source, player) assert_true(result.valid, "Should be valid when all requirements met") ability_system.free() func test_validate_combined_cost_fails_on_cp() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 5, "dull_self": true} var source = _create_mock_card() source.activate() var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 2) # Insufficient var result = ability_system._validate_ability_cost(cost, source, player) assert_false(result.valid, "Should fail on CP requirement") ability_system.free() func test_validate_combined_cost_fails_on_dull() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "dull_self": true} var source = _create_mock_card() source.dull() # Already dull var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 5) var result = ability_system._validate_ability_cost(cost, source, player) assert_false(result.valid, "Should fail on dull requirement") ability_system.free() # ============================================================================= # COST PAYMENT TESTS # ============================================================================= func test_pay_empty_cost() -> void: var ability_system = AbilitySystem.new() var cost = {} var player = MockPlayer.new() var success = ability_system._pay_ability_cost(cost, null, player) assert_true(success, "Paying empty cost should succeed") ability_system.free() func test_pay_generic_cp_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 3} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 5) var initial_cp = player.cp_pool.get_total_cp() var success = ability_system._pay_ability_cost(cost, null, player) assert_true(success, "Should successfully pay cost") assert_eq(player.cp_pool.get_total_cp(), initial_cp - 3, "Should spend 3 CP") ability_system.free() func test_pay_specific_element_cp_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "element": "FIRE"} var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 4) player.cp_pool.add_cp(Enums.Element.ICE, 3) var success = ability_system._pay_ability_cost(cost, null, player) assert_true(success, "Should successfully pay cost") assert_eq(player.cp_pool.get_cp(Enums.Element.FIRE), 2, "Should spend 2 Fire CP") assert_eq(player.cp_pool.get_cp(Enums.Element.ICE), 3, "Ice CP should be unchanged") ability_system.free() func test_pay_dull_self_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"dull_self": true} var source = _create_mock_card() source.activate() var player = MockPlayer.new() assert_true(source.is_active(), "Source should start active") var success = ability_system._pay_ability_cost(cost, source, player) assert_true(success, "Should successfully pay cost") assert_true(source.is_dull(), "Source should be dulled") ability_system.free() func test_pay_combined_cost() -> void: var ability_system = AbilitySystem.new() var cost = {"cp": 2, "dull_self": true} var source = _create_mock_card() source.activate() var player = MockPlayer.new() player.cp_pool.add_cp(Enums.Element.FIRE, 5) var success = ability_system._pay_ability_cost(cost, source, player) assert_true(success, "Should successfully pay combined cost") assert_eq(player.cp_pool.get_total_cp(), 3, "Should spend 2 CP") assert_true(source.is_dull(), "Source should be dulled") ability_system.free() # ============================================================================= # SIGNAL TESTS # ============================================================================= func test_ability_cost_failed_signal_declared() -> void: var ability_system = AbilitySystem.new() # Check signal exists var signal_exists = ability_system.has_signal("ability_cost_failed") assert_true(signal_exists, "AbilitySystem should have ability_cost_failed signal") ability_system.free() # ============================================================================= # HELPER FUNCTIONS # ============================================================================= func _create_mock_card() -> CardInstance: var card = CardInstance.new() var data = CardDatabase.CardData.new() data.type = Enums.CardType.FORWARD data.power = 5000 data.cost = 3 data.name = "Test Card" data.elements = [Enums.Element.FIRE] card.card_data = data card.current_power = 5000 return card func _create_mock_card_with_name(card_name: String) -> CardInstance: var card = _create_mock_card() card.card_data.name = card_name return card # ============================================================================= # MOCK CLASSES # ============================================================================= class MockPlayer: var cp_pool: CPPool var hand: Zone func _init(): cp_pool = CPPool.new() hand = Zone.new(Enums.ZoneType.HAND, 0)