extends GutTest ## Tests for the ConditionChecker class ## Tests various condition types and logical operators # ============================================================================= # SETUP # ============================================================================= var checker: ConditionChecker func before_each() -> void: checker = ConditionChecker.new() # ============================================================================= # BASIC TESTS # ============================================================================= func test_checker_instantiates() -> void: assert_not_null(checker, "ConditionChecker should instantiate") func test_empty_condition_returns_true() -> void: var result = checker.evaluate({}, {}) assert_true(result, "Empty condition should return true (unconditional)") func test_unknown_condition_type_returns_false() -> void: var condition = {"type": "NONEXISTENT_TYPE"} var result = checker.evaluate(condition, {}) assert_false(result, "Unknown condition type should return false") # ============================================================================= # COMPARISON HELPER TESTS # ============================================================================= func test_compare_eq() -> void: assert_true(checker._compare(5, "EQ", 5), "5 == 5") assert_false(checker._compare(5, "EQ", 3), "5 != 3") func test_compare_neq() -> void: assert_true(checker._compare(5, "NEQ", 3), "5 != 3") assert_false(checker._compare(5, "NEQ", 5), "5 == 5") func test_compare_gt() -> void: assert_true(checker._compare(5, "GT", 3), "5 > 3") assert_false(checker._compare(5, "GT", 5), "5 not > 5") assert_false(checker._compare(3, "GT", 5), "3 not > 5") func test_compare_gte() -> void: assert_true(checker._compare(5, "GTE", 3), "5 >= 3") assert_true(checker._compare(5, "GTE", 5), "5 >= 5") assert_false(checker._compare(3, "GTE", 5), "3 not >= 5") func test_compare_lt() -> void: assert_true(checker._compare(3, "LT", 5), "3 < 5") assert_false(checker._compare(5, "LT", 5), "5 not < 5") assert_false(checker._compare(5, "LT", 3), "5 not < 3") func test_compare_lte() -> void: assert_true(checker._compare(3, "LTE", 5), "3 <= 5") assert_true(checker._compare(5, "LTE", 5), "5 <= 5") assert_false(checker._compare(5, "LTE", 3), "5 not <= 3") # ============================================================================= # LOGICAL OPERATOR TESTS # ============================================================================= func test_and_with_all_true() -> void: var condition = { "type": "AND", "conditions": [ {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 3}, {"type": "DAMAGE_RECEIVED", "comparison": "LTE", "value": 5} ] } var context = _create_mock_context_with_damage(4) var result = checker.evaluate(condition, context) assert_true(result, "AND with all true conditions should return true") func test_and_with_one_false() -> void: var condition = { "type": "AND", "conditions": [ {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 3}, {"type": "DAMAGE_RECEIVED", "comparison": "LTE", "value": 2} ] } var context = _create_mock_context_with_damage(4) var result = checker.evaluate(condition, context) assert_false(result, "AND with one false condition should return false") func test_or_with_one_true() -> void: var condition = { "type": "OR", "conditions": [ {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 10}, {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 3} ] } var context = _create_mock_context_with_damage(5) var result = checker.evaluate(condition, context) assert_true(result, "OR with one true condition should return true") func test_or_with_all_false() -> void: var condition = { "type": "OR", "conditions": [ {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 10}, {"type": "DAMAGE_RECEIVED", "comparison": "EQ", "value": 0} ] } var context = _create_mock_context_with_damage(5) var result = checker.evaluate(condition, context) assert_false(result, "OR with all false conditions should return false") func test_not_inverts_true() -> void: var condition = { "type": "NOT", "condition": {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 10} } var context = _create_mock_context_with_damage(5) var result = checker.evaluate(condition, context) assert_true(result, "NOT should invert false to true") func test_not_inverts_false() -> void: var condition = { "type": "NOT", "condition": {"type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 3} } var context = _create_mock_context_with_damage(5) var result = checker.evaluate(condition, context) assert_false(result, "NOT should invert true to false") # ============================================================================= # DAMAGE_RECEIVED CONDITION TESTS # ============================================================================= func test_damage_received_gte() -> void: var condition = { "type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 5 } # Not enough damage var context = _create_mock_context_with_damage(3) assert_false(checker.evaluate(condition, context), "3 damage not >= 5") # Exactly enough context = _create_mock_context_with_damage(5) assert_true(checker.evaluate(condition, context), "5 damage >= 5") # More than enough context = _create_mock_context_with_damage(7) assert_true(checker.evaluate(condition, context), "7 damage >= 5") func test_damage_received_no_game_state() -> void: var condition = { "type": "DAMAGE_RECEIVED", "comparison": "GTE", "value": 5 } var context = {"game_state": null, "player_id": 0} var result = checker.evaluate(condition, context) assert_false(result, "Should return false without game state") # ============================================================================= # FORWARD STATE TESTS # ============================================================================= func test_forward_state_dull() -> void: var condition = { "type": "FORWARD_STATE", "state": "DULL", "check_self": false } # Create mock card var card = _create_mock_forward() card.is_dull = true var context = {"target_card": card} assert_true(checker.evaluate(condition, context), "Dull card should match DULL state") card.is_dull = false assert_false(checker.evaluate(condition, context), "Active card should not match DULL state") card.free() func test_forward_state_active() -> void: var condition = { "type": "FORWARD_STATE", "state": "ACTIVE", "check_self": false } var card = _create_mock_forward() card.is_dull = false var context = {"target_card": card} assert_true(checker.evaluate(condition, context), "Active card should match ACTIVE state") card.is_dull = true assert_false(checker.evaluate(condition, context), "Dull card should not match ACTIVE state") card.free() func test_forward_state_check_self() -> void: var condition = { "type": "FORWARD_STATE", "state": "DULL", "check_self": true } var source_card = _create_mock_forward() source_card.is_dull = true var context = {"source_card": source_card, "target_card": null} assert_true(checker.evaluate(condition, context), "check_self=true should use source_card") source_card.free() func test_forward_state_no_card() -> void: var condition = { "type": "FORWARD_STATE", "state": "DULL", "check_self": false } var context = {"target_card": null} assert_false(checker.evaluate(condition, context), "Should return false without target card") # ============================================================================= # COST COMPARISON TESTS # ============================================================================= func test_cost_comparison_lte() -> void: var condition = { "type": "COST_COMPARISON", "comparison": "LTE", "value": 3 } var card = _create_mock_forward_with_cost(2) var context = {"target_card": card} assert_true(checker.evaluate(condition, context), "Cost 2 <= 3") card.card_data.cost = 3 assert_true(checker.evaluate(condition, context), "Cost 3 <= 3") card.card_data.cost = 5 assert_false(checker.evaluate(condition, context), "Cost 5 not <= 3") card.free() func test_cost_comparison_gte() -> void: var condition = { "type": "COST_COMPARISON", "comparison": "GTE", "value": 4 } var card = _create_mock_forward_with_cost(5) var context = {"target_card": card} assert_true(checker.evaluate(condition, context), "Cost 5 >= 4") card.card_data.cost = 4 assert_true(checker.evaluate(condition, context), "Cost 4 >= 4") card.card_data.cost = 3 assert_false(checker.evaluate(condition, context), "Cost 3 not >= 4") card.free() # ============================================================================= # POWER COMPARISON TESTS # ============================================================================= func test_power_comparison_lt_value() -> void: var condition = { "type": "POWER_COMPARISON", "comparison": "LT", "value": 8000 } var card = _create_mock_forward_with_power(5000) var context = {"target_card": card} assert_true(checker.evaluate(condition, context), "Power 5000 < 8000") card.current_power = 8000 assert_false(checker.evaluate(condition, context), "Power 8000 not < 8000") card.free() func test_power_comparison_self_power() -> void: var condition = { "type": "POWER_COMPARISON", "comparison": "LT", "compare_to": "SELF_POWER" } var attacker = _create_mock_forward_with_power(8000) var blocker = _create_mock_forward_with_power(5000) var context = { "source_card": attacker, "target_card": blocker } assert_true(checker.evaluate(condition, context), "Blocker 5000 < Attacker 8000") blocker.current_power = 9000 assert_false(checker.evaluate(condition, context), "Blocker 9000 not < Attacker 8000") attacker.free() blocker.free() # ============================================================================= # HELPER FUNCTIONS # ============================================================================= func _create_mock_context_with_damage(damage: int) -> Dictionary: var mock_game_state = MockGameState.new(damage) return { "game_state": mock_game_state, "player_id": 0 } func _create_mock_forward() -> CardInstance: var card = CardInstance.new() var data = CardDatabase.CardData.new() data.type = Enums.CardType.FORWARD data.cost = 3 data.power = 7000 card.card_data = data card.is_dull = false return card func _create_mock_forward_with_cost(cost: int) -> CardInstance: var card = _create_mock_forward() card.card_data.cost = cost return card func _create_mock_forward_with_power(power: int) -> CardInstance: var card = _create_mock_forward() card.card_data.power = power card.current_power = power return card # ============================================================================= # MOCK CLASSES # ============================================================================= class MockGameState: var players: Array func _init(player_damage: int = 0): players = [MockPlayer.new(player_damage), MockPlayer.new(0)] func get_player_damage(player_id: int) -> int: if player_id < players.size(): return players[player_id].damage return 0 func get_field_cards(player_id: int) -> Array: if player_id < players.size(): return players[player_id].field return [] func get_break_zone(player_id: int) -> Array: if player_id < players.size(): return players[player_id].break_zone return [] class MockPlayer: var damage: int = 0 var field: Array = [] var break_zone: Array = [] func _init(p_damage: int = 0): damage = p_damage