Files
tekton/tests/test_gauntlet_cleanser.gd
T

116 lines
4.9 KiB
GDScript

extends GutTest
# =============================================================================
# Test: Gauntlet Cleanser Power-Up (v2) [Gauntlet #072]
# Covers grant cadence (every 2 missions, max 1), 5-cell immunity lifecycle,
# sticky clearing, stun-blocked activation, and the safe-stop early termination.
# Runs headless; uses a GridMap mock so clear_sticky_cell can run locally.
# =============================================================================
const GauntletManager = preload("res://scripts/managers/gauntlet_manager.gd")
const GridMapMock = preload("res://tests/helpers/gridmap_mock.gd")
const MainMock = preload("res://tests/helpers/main_mock.gd")
var manager
var main_mock: Node
var gridmap_mock: Node
func before_each():
main_mock = MainMock.new()
add_child(main_mock)
gridmap_mock = GridMapMock.new()
gridmap_mock.name = "EnhancedGridMap"
main_mock.add_child(gridmap_mock)
manager = GauntletManager.new()
main_mock.add_child(manager)
manager.initialize(main_mock, gridmap_mock)
manager.current_phase = 0
func after_each():
if main_mock:
main_mock.queue_free()
func _without_peer(fn: Callable) -> void:
var saved = multiplayer.multiplayer_peer
multiplayer.multiplayer_peer = null
fn.call()
multiplayer.multiplayer_peer = saved
# =============================================================================
# Grant cadence: every 2 missions, inventory max 1
# =============================================================================
func test_no_cleanser_after_one_mission():
manager._on_goal_count_updated(7, 1)
assert_eq(manager.player_cleansers.get(7, 0), 0, "No cleanser after 1 mission")
func test_cleanser_granted_after_two_missions():
manager._on_goal_count_updated(7, 1)
manager._on_goal_count_updated(7, 2)
assert_eq(manager.player_cleansers.get(7, 0), 1, "Cleanser granted after 2 missions")
func test_cleanser_inventory_capped_at_one():
# Four missions would be two grants, but inventory caps at 1 (not consumed).
for i in range(4):
manager._on_goal_count_updated(7, i + 1)
assert_eq(manager.player_cleansers.get(7, 0), 1, "Inventory never exceeds 1")
# =============================================================================
# Activation / immunity lifecycle
# =============================================================================
func test_use_cleanser_cell_decrements_until_exhausted():
manager.cleanser_active[3] = true
manager.cleanser_cells_left[3] = manager.CLEANSER_MAX_CELLS
# First 4 uses keep it active...
for i in range(manager.CLEANSER_MAX_CELLS - 1):
assert_true(manager.use_cleanser_cell(3), "Still active on use %d" % (i + 1))
# ...the 5th use exhausts it.
assert_false(manager.use_cleanser_cell(3), "Exhausted after 5th cell")
assert_false(manager.is_cleanser_active(3), "Deactivated after 5th cell")
func test_use_cleanser_cell_when_inactive_returns_false():
assert_false(manager.use_cleanser_cell(99), "Inactive cleanser use returns false")
func test_deactivate_clears_state():
manager.cleanser_active[5] = true
manager.cleanser_cells_left[5] = 3
manager.deactivate_cleanser(5)
assert_false(manager.is_cleanser_active(5), "Deactivated")
assert_false(manager.cleanser_cells_left.has(5), "Cells-left cleared")
# =============================================================================
# Sticky clearing
# =============================================================================
func test_clear_sticky_cell_removes_and_protects():
manager.sticky_cells[Vector2i(4, 4)] = true
_without_peer(func():
manager.clear_sticky_cell(Vector2i(4, 4))
)
assert_false(manager.is_sticky_cell(Vector2i(4, 4)), "Sticky removed")
assert_true(manager.is_cleansed_cell(Vector2i(4, 4)), "Cleared cell gets regrowth protection")
# Layer-2 overlay cleared (mock records -1 = erased).
assert_eq(gridmap_mock.get_cell_item(Vector3i(4, 2, 4)), -1, "Layer-2 sticky overlay cleared")
# =============================================================================
# Safe-stop early termination (#072 acceptance: ends when stopping on safe cell)
# =============================================================================
func test_stop_on_safe_cell_ends_cleanser():
manager.cleanser_active[8] = true
manager.cleanser_cells_left[8] = 3
manager.notify_movement_stopped(8, Vector2i(5, 5)) # safe cell
assert_false(manager.is_cleanser_active(8), "Cleanser ends on safe-cell stop")
func test_stop_on_sticky_cell_keeps_cleanser():
manager.sticky_cells[Vector2i(6, 6)] = true
manager.cleanser_active[8] = true
manager.cleanser_cells_left[8] = 3
manager.notify_movement_stopped(8, Vector2i(6, 6)) # still on sticky
assert_true(manager.is_cleanser_active(8), "Cleanser persists while still on sticky")
func test_notify_stop_noop_without_cleanser():
# Should not crash or change anything when the player has no cleanser.
manager.notify_movement_stopped(123, Vector2i(5, 5))
assert_false(manager.is_cleanser_active(123), "No cleanser → no-op")