Files
FFCardGame/tests/unit/test_condition_checker.gd
2026-02-02 16:28:53 -05:00

421 lines
11 KiB
GDScript

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