feature updates
This commit is contained in:
348
tests/unit/test_cost_validation.gd
Normal file
348
tests/unit/test_cost_validation.gd
Normal file
@@ -0,0 +1,348 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user