extends GutTest ## Tests for the Modal Choice System (CHOOSE_MODE effects) ## Tests parser output, ChoiceModal UI, and AbilitySystem integration # ============================================================================= # PARSER OUTPUT TESTS # ============================================================================= func test_modal_effect_has_correct_structure() -> void: # Simulate a parsed CHOOSE_MODE effect var effect = { "type": "CHOOSE_MODE", "select_count": 1, "select_up_to": false, "mode_count": 3, "modes": [ { "index": 0, "description": "Choose 1 Forward. Deal it 7000 damage.", "effects": [{"type": "DAMAGE", "amount": 7000}] }, { "index": 1, "description": "Choose 1 Monster. Break it.", "effects": [{"type": "BREAK"}] }, { "index": 2, "description": "Deal 3000 damage to all Forwards.", "effects": [{"type": "DAMAGE", "amount": 3000}] } ] } assert_eq(effect.type, "CHOOSE_MODE", "Effect type should be CHOOSE_MODE") assert_eq(effect.select_count, 1, "Should select 1 mode") assert_eq(effect.mode_count, 3, "Should have 3 modes") assert_eq(effect.modes.size(), 3, "Modes array should have 3 entries") assert_false(effect.select_up_to, "Should not be 'up to' selection") func test_modal_effect_with_enhanced_condition() -> void: var effect = { "type": "CHOOSE_MODE", "select_count": 1, "select_up_to": false, "mode_count": 3, "modes": [], "enhanced_condition": { "description": "if you have 5 or more ifrit in your break zone", "select_count": 3, "select_up_to": true } } assert_true(effect.has("enhanced_condition"), "Should have enhanced condition") assert_eq(effect.enhanced_condition.select_count, 3, "Enhanced should allow 3 selections") assert_true(effect.enhanced_condition.select_up_to, "Enhanced should be 'up to'") func test_modal_mode_has_description_and_effects() -> void: var mode = { "index": 0, "description": "Draw 2 cards.", "effects": [{"type": "DRAW", "amount": 2}] } assert_true(mode.has("description"), "Mode should have description") assert_true(mode.has("effects"), "Mode should have effects array") assert_eq(mode.effects.size(), 1, "Mode should have 1 effect") assert_eq(mode.effects[0].type, "DRAW", "Effect should be DRAW") # ============================================================================= # CHOICE MODAL TESTS # ============================================================================= func test_choice_modal_instantiates() -> void: var modal = ChoiceModal.new() assert_not_null(modal, "ChoiceModal should instantiate") modal.free() func test_choice_modal_starts_invisible() -> void: var modal = ChoiceModal.new() add_child_autofree(modal) # Need to wait for _ready to complete await get_tree().process_frame assert_false(modal.visible, "ChoiceModal should start invisible") func test_choice_modal_has_correct_layer() -> void: var modal = ChoiceModal.new() add_child_autofree(modal) await get_tree().process_frame assert_eq(modal.layer, 200, "ChoiceModal should be at layer 200") func test_choice_modal_signals_exist() -> void: var modal = ChoiceModal.new() assert_true(modal.has_signal("choice_made"), "Should have choice_made signal") assert_true(modal.has_signal("choice_cancelled"), "Should have choice_cancelled signal") modal.free() # ============================================================================= # EFFECT RESOLVER TESTS # ============================================================================= func test_effect_resolver_has_choice_required_signal() -> void: var resolver = EffectResolver.new() assert_true(resolver.has_signal("choice_required"), "Should have choice_required signal") func test_effect_resolver_emits_choice_required_for_choose_mode() -> void: var resolver = EffectResolver.new() var signal_received = false var received_effect = {} var received_modes = [] resolver.choice_required.connect(func(effect, modes): signal_received = true received_effect = effect received_modes = modes ) var effect = { "type": "CHOOSE_MODE", "modes": [ {"index": 0, "description": "Option 1", "effects": []}, {"index": 1, "description": "Option 2", "effects": []} ] } # Resolve the effect resolver.resolve(effect, null, [], null) assert_true(signal_received, "Should emit choice_required signal") assert_eq(received_modes.size(), 2, "Should pass modes to signal") # ============================================================================= # FIELD EFFECT MANAGER TESTS # ============================================================================= func test_field_effect_manager_block_immunity_empty() -> void: var manager = FieldEffectManager.new() # With no abilities registered, should return false var result = manager.has_block_immunity(null, null, null) assert_false(result, "Should return false with no abilities") func test_field_effect_manager_attack_restriction_empty() -> void: var manager = FieldEffectManager.new() var result = manager.has_attack_restriction(null, null) assert_false(result, "Should return false with no abilities") func test_field_effect_manager_block_restriction_empty() -> void: var manager = FieldEffectManager.new() var result = manager.has_block_restriction(null, null) assert_false(result, "Should return false with no abilities") func test_field_effect_manager_taunt_targets_empty() -> void: var manager = FieldEffectManager.new() var result = manager.get_taunt_targets(0, null) assert_eq(result.size(), 0, "Should return empty array with no abilities") func test_field_effect_manager_cost_modifier_empty() -> void: var manager = FieldEffectManager.new() var result = manager.get_cost_modifier(null, 0, null) assert_eq(result, 0, "Should return 0 with no abilities") func test_field_effect_manager_max_attacks_default() -> void: var manager = FieldEffectManager.new() var result = manager.get_max_attacks(null, null) assert_eq(result, 1, "Default max attacks should be 1") # ============================================================================= # BLOCKER IMMUNITY CONDITION TESTS # ============================================================================= func test_blocker_immunity_condition_empty() -> void: var manager = FieldEffectManager.new() # Empty condition means unconditional immunity var result = manager._blocker_matches_immunity_condition(null, {}, null) assert_true(result, "Empty condition should return true (unconditional)") func test_blocker_immunity_condition_cost_gte() -> void: var manager = FieldEffectManager.new() # Create mock card data var blocker = _create_mock_card(3, 5000) # cost 3, power 5000 var condition = { "comparison": "GTE", "attribute": "cost", "value": 4 } var result = manager._blocker_matches_immunity_condition(blocker, condition, null) assert_false(result, "Cost 3 is not >= 4") blocker.card_data.cost = 4 result = manager._blocker_matches_immunity_condition(blocker, condition, null) assert_true(result, "Cost 4 is >= 4") blocker.free() func test_blocker_immunity_condition_power_lt_self() -> void: var manager = FieldEffectManager.new() var blocker = _create_mock_card(3, 5000) var attacker = _create_mock_card(4, 8000) var condition = { "comparison": "LT", "attribute": "power", "compare_to": "SELF_POWER" } # Blocker power 5000 < attacker power 8000 var result = manager._blocker_matches_immunity_condition(blocker, condition, attacker) assert_true(result, "5000 < 8000 should be true") # Change blocker power to be higher blocker.current_power = 9000 result = manager._blocker_matches_immunity_condition(blocker, condition, attacker) assert_false(result, "9000 < 8000 should be false") blocker.free() attacker.free() # ============================================================================= # ABILITY SYSTEM INTEGRATION TESTS # ============================================================================= func test_ability_system_has_choice_modal_reference() -> void: # Check that AbilitySystem has the choice_modal variable var ability_system_script = load("res://scripts/game/abilities/AbilitySystem.gd") assert_not_null(ability_system_script, "AbilitySystem script should exist") func test_modes_selected_queues_effects() -> void: # This tests the logic of _on_modes_selected indirectly var effect = { "type": "CHOOSE_MODE", "modes": [ {"index": 0, "description": "Deal damage", "effects": [{"type": "DAMAGE", "amount": 5000}]}, {"index": 1, "description": "Draw cards", "effects": [{"type": "DRAW", "amount": 2}]} ] } var modes = effect.modes var selected_indices = [1] # Player selected option 2 (draw) # Verify mode selection logic var queued_effects = [] for index in selected_indices: if index >= 0 and index < modes.size(): var mode = modes[index] for mode_effect in mode.get("effects", []): queued_effects.append(mode_effect) assert_eq(queued_effects.size(), 1, "Should queue 1 effect") assert_eq(queued_effects[0].type, "DRAW", "Queued effect should be DRAW") assert_eq(queued_effects[0].amount, 2, "Draw amount should be 2") func test_multi_select_queues_multiple_effects() -> void: var effect = { "type": "CHOOSE_MODE", "select_count": 2, "modes": [ {"index": 0, "effects": [{"type": "DAMAGE", "amount": 5000}]}, {"index": 1, "effects": [{"type": "DRAW", "amount": 2}]}, {"index": 2, "effects": [{"type": "BREAK"}]} ] } var modes = effect.modes var selected_indices = [0, 2] # Player selected damage and break var queued_effects = [] for index in selected_indices: if index >= 0 and index < modes.size(): var mode = modes[index] for mode_effect in mode.get("effects", []): queued_effects.append(mode_effect) assert_eq(queued_effects.size(), 2, "Should queue 2 effects") assert_eq(queued_effects[0].type, "DAMAGE", "First effect should be DAMAGE") assert_eq(queued_effects[1].type, "BREAK", "Second effect should be BREAK") # ============================================================================= # ENHANCED CONDITION TESTS # ============================================================================= func test_enhanced_condition_parsing() -> void: var condition = { "description": "if you have a total of 5 or more card name ifrita and/or card name ifrit in your break zone", "select_count": 3, "select_up_to": true } # Test that description contains expected keywords assert_true("break zone" in condition.description, "Should mention break zone") assert_true("5 or more" in condition.description, "Should mention count requirement") func test_regex_count_extraction() -> void: var description = "if you have 5 or more ifrit in your break zone" var regex = RegEx.new() regex.compile(r"(\d+) or more") var match_result = regex.search(description) assert_not_null(match_result, "Should find count pattern") assert_eq(match_result.get_string(1), "5", "Should extract '5'") assert_eq(int(match_result.get_string(1)), 5, "Should convert to int 5") # ============================================================================= # HELPER FUNCTIONS # ============================================================================= func _create_mock_card(cost: int, power: int) -> CardInstance: var card = CardInstance.new() # Create minimal card data var data = CardDatabase.CardData.new() data.cost = cost data.power = power data.type = Enums.CardType.FORWARD card.card_data = data card.current_power = power return card