160 lines
6.2 KiB
GDScript
160 lines
6.2 KiB
GDScript
extends GutTest
|
|
|
|
# =============================================================================
|
|
# Test: Gauntlet Growth Tick System (v2) [Gauntlet #067]
|
|
# Replaces the old cannon-timer test. Covers growth timing, phase configs,
|
|
# candidate generation, cells-per-tick ranges, weighted selection, and
|
|
# cleansed-cell exclusion.
|
|
# =============================================================================
|
|
|
|
const GauntletManager = preload("res://scripts/managers/gauntlet_manager.gd")
|
|
var gauntlet_manager: Node
|
|
var main_mock: Node
|
|
var gridmap_mock: Node
|
|
|
|
func before_all():
|
|
gut.p("=== Feature Tests [Gauntlet #067 Growth Tick] ===")
|
|
|
|
func before_each():
|
|
main_mock = Node.new()
|
|
add_child(main_mock)
|
|
gridmap_mock = Node.new()
|
|
gridmap_mock.name = "EnhancedGridMap"
|
|
main_mock.add_child(gridmap_mock)
|
|
|
|
gauntlet_manager = GauntletManager.new()
|
|
main_mock.add_child(gauntlet_manager)
|
|
gauntlet_manager.initialize(main_mock, gridmap_mock)
|
|
|
|
func after_each():
|
|
if main_mock:
|
|
main_mock.queue_free()
|
|
|
|
func after_all():
|
|
gut.p("=== Feature Tests Complete ===")
|
|
|
|
# =============================================================================
|
|
# Growth Timing
|
|
# =============================================================================
|
|
|
|
func test_growth_timer_starts_zero():
|
|
assert_eq(gauntlet_manager.growth_timer, 0.0, "Growth timer starts at 0.0")
|
|
|
|
func test_growth_interval_default():
|
|
assert_eq(gauntlet_manager.growth_interval, 3.0, "Growth interval defaults to 3.0s")
|
|
|
|
func test_telegraph_duration_default():
|
|
assert_eq(gauntlet_manager.telegraph_duration, 1.0, "Telegraph duration defaults to 1.0s")
|
|
|
|
# =============================================================================
|
|
# Phase Growth Config
|
|
# =============================================================================
|
|
|
|
func test_phase_growth_config_has_three_phases():
|
|
assert_eq(gauntlet_manager.phase_growth_config.size(), 3, "Three phase growth configs")
|
|
|
|
func test_phase1_cells_range():
|
|
var cfg = gauntlet_manager.phase_growth_config[0]
|
|
assert_eq(cfg["cells_min"], 4, "Phase 1 min 4 cells/tick")
|
|
assert_eq(cfg["cells_max"], 6, "Phase 1 max 6 cells/tick")
|
|
|
|
func test_phase2_cells_range():
|
|
var cfg = gauntlet_manager.phase_growth_config[1]
|
|
assert_eq(cfg["cells_min"], 6, "Phase 2 min 6 cells/tick")
|
|
assert_eq(cfg["cells_max"], 8, "Phase 2 max 8 cells/tick")
|
|
|
|
func test_phase3_cells_range():
|
|
var cfg = gauntlet_manager.phase_growth_config[2]
|
|
assert_eq(cfg["cells_min"], 8, "Phase 3 min 8 cells/tick")
|
|
assert_eq(cfg["cells_max"], 10, "Phase 3 max 10 cells/tick")
|
|
|
|
func test_cells_this_tick_in_phase_range():
|
|
for phase in range(3):
|
|
gauntlet_manager.current_phase = phase
|
|
var cfg = gauntlet_manager.phase_growth_config[phase]
|
|
# Sample several times since the count is randomized.
|
|
for _i in range(20):
|
|
var n = gauntlet_manager._cells_this_tick()
|
|
assert_true(n >= cfg["cells_min"] and n <= cfg["cells_max"],
|
|
"Phase %d cells/tick %d within [%d,%d]" % [phase, n, cfg["cells_min"], cfg["cells_max"]])
|
|
|
|
# =============================================================================
|
|
# Candidate Generation
|
|
# =============================================================================
|
|
|
|
func test_candidates_are_all_safe_cells():
|
|
gauntlet_manager.current_phase = 0
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
# Fresh arena: every playable cell is SAFE.
|
|
assert_eq(candidates.size(), gauntlet_manager.playable_cell_count(),
|
|
"All playable cells are candidates on a fresh arena")
|
|
|
|
func test_candidates_exclude_sticky():
|
|
gauntlet_manager.sticky_cells[Vector2i(3, 3)] = true
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
var found := false
|
|
for c in candidates:
|
|
if c["pos"] == Vector2i(3, 3):
|
|
found = true
|
|
assert_false(found, "Sticky cells are excluded from candidates")
|
|
|
|
func test_candidates_exclude_cleansed():
|
|
gauntlet_manager.mark_cleansed(Vector2i(4, 4))
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
var found := false
|
|
for c in candidates:
|
|
if c["pos"] == Vector2i(4, 4):
|
|
found = true
|
|
assert_false(found, "Cleansed cells are excluded from candidates (regrowth protection)")
|
|
|
|
func test_candidates_exclude_npc_and_boundary():
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
for c in candidates:
|
|
var p = c["pos"]
|
|
assert_false(gauntlet_manager._is_npc_zone(p), "No NPC-zone candidates")
|
|
assert_false(gauntlet_manager._is_boundary(p), "No boundary candidates")
|
|
|
|
func test_candidates_have_scores():
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
assert_true(candidates.size() > 0, "Has candidates")
|
|
assert_true(candidates[0].has("score"), "Candidate carries a score")
|
|
|
|
# =============================================================================
|
|
# Weighted Selection
|
|
# =============================================================================
|
|
|
|
func test_select_count_respected():
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
var picked = gauntlet_manager._select_cells_weighted(candidates, 5)
|
|
assert_eq(picked.size(), 5, "Selects exactly the requested count")
|
|
|
|
func test_select_no_duplicates():
|
|
var candidates = gauntlet_manager._generate_candidates()
|
|
var picked = gauntlet_manager._select_cells_weighted(candidates, 10)
|
|
var seen := {}
|
|
for p in picked:
|
|
assert_false(seen.has(p), "No duplicate selections")
|
|
seen[p] = true
|
|
|
|
func test_select_capped_at_pool_size():
|
|
var small = [{"pos": Vector2i(2, 2), "score": 1.0}, {"pos": Vector2i(2, 3), "score": 1.0}]
|
|
var picked = gauntlet_manager._select_cells_weighted(small, 10)
|
|
assert_eq(picked.size(), 2, "Cannot select more than pool size")
|
|
|
|
# =============================================================================
|
|
# Scoring Helpers
|
|
# =============================================================================
|
|
|
|
func test_layer_classification():
|
|
assert_eq(gauntlet_manager._layer_of(Vector2i(9, 9)), "inner", "Center is inner")
|
|
assert_eq(gauntlet_manager._layer_of(Vector2i(1, 1)), "outer", "Corner is outer")
|
|
|
|
func test_sticky_neighbor_count():
|
|
gauntlet_manager.sticky_cells[Vector2i(5, 5)] = true
|
|
gauntlet_manager.sticky_cells[Vector2i(5, 6)] = true
|
|
assert_eq(gauntlet_manager._sticky_neighbor_count(Vector2i(6, 5)), 2,
|
|
"Counts 8-directional sticky neighbors")
|
|
|
|
func test_chebyshev():
|
|
assert_eq(gauntlet_manager._chebyshev(Vector2i(0, 0), Vector2i(3, 1)), 3, "Chebyshev distance")
|