- Implement test for popup anchor behavior in rule-builder menus to ensure consistent anchor positioning during menu transitions. - Create tests for stage logic, including mode transitions, toolbar visibility, and status bar updates. - Add terrain drag-painting tests to verify correct block placement behavior and conflict handling. - Introduce walk waypoint tests to check for arrival conditions and position stability after navigation.
102 lines
3.6 KiB
GDScript
102 lines
3.6 KiB
GDScript
# test_phase4b_grid_dirty.gd
|
|
# Headless checks for the Phase 4b grid spatial dictionary lifecycle and the
|
|
# WS3 TriggerArea-move redraw bugfix:
|
|
# 1. After placing a block, its cells are in the dictionary.
|
|
# 2. Moving a block via transform_committed moves its occupancy (old cells gone).
|
|
# 3. Deleting a block removes its cells (no stale entries).
|
|
# 4. _on_transform_committed marks StageDirectorVisuals dirty (TriggerArea move
|
|
# refreshes the dashed rule connector).
|
|
#
|
|
# Run with:
|
|
# & "C:\Godot4\Godot_v4.7.1-stable_win64_console.exe" --headless --script res://tests/test_phase4b_grid_dirty.gd --path .
|
|
#
|
|
# Prints PASS/FAIL per assertion and exits 0 on all PASS, 1 on any FAIL.
|
|
|
|
extends SceneTree
|
|
|
|
const STAGE_SCENE := preload("res://scenes/sandbox_stage.tscn")
|
|
const TERRAIN_UTILS := preload("res://scripts/terrain_utils.gd")
|
|
const STAGE_SPAWNER := preload("res://scripts/stage_spawner.gd")
|
|
const TRIGGER_AREA := preload("res://scripts/trigger_area.gd")
|
|
|
|
var _checks := 0
|
|
var _failures := 0
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
|
|
func _run() -> void:
|
|
print("")
|
|
print("========================================================")
|
|
print(" PHASE 4b GRID DICT / DIRTY-FLAG TEST (headless)")
|
|
print("========================================================")
|
|
var stage: Node2D = STAGE_SCENE.instantiate()
|
|
root.add_child(stage)
|
|
var world: Node2D = stage._world
|
|
|
|
# --- Place a ground block at cell (0,0) through the spawner path ---
|
|
var block = stage._spawner.spawn("ground", stage._terrain_cell_center(Vector2i(0, 0)))
|
|
_check(block != null, "ground block spawns")
|
|
_check((block as TerrainBlock).spawn_id == "ground", "terrain block carries spawn_id 'ground'")
|
|
stage._rebuild_grid_cells()
|
|
var cell00 := Vector2i(0, 0)
|
|
_check(not stage._grid_cells.get(cell00, []).is_empty(),
|
|
"cell (0,0) occupied after place")
|
|
|
|
# --- Move it +400 x via the committed-transform path ---
|
|
block.position += Vector2(400.0, 0.0)
|
|
var moved_nodes: Array[Node2D] = [block as Node2D]
|
|
stage._on_transform_committed(moved_nodes)
|
|
_check(stage._grid_cells.get(cell00, []).is_empty(),
|
|
"old cell (0,0) no longer occupied after move")
|
|
var new_cell := Vector2i(25, 0)
|
|
_check(not stage._grid_cells.get(new_cell, []).is_empty(),
|
|
"new cell (%s) occupied after move" % new_cell)
|
|
|
|
# --- Delete it via the stage delete path ---
|
|
stage._selection.select_only(block)
|
|
stage.delete_selected()
|
|
_check(stage._grid_cells.get(new_cell, []).is_empty(),
|
|
"cell (%s) cleared after delete (no stale entries)" % new_cell)
|
|
await process_frame
|
|
|
|
# --- TriggerArea move -> director visuals mark_dirty ---
|
|
var visuals = stage._director_visuals
|
|
visuals._dirty = false
|
|
var area: Node2D = TRIGGER_AREA.new()
|
|
area.position = Vector2(0.0, 0.0)
|
|
world.add_child(area)
|
|
var rules_arr: Array[Dictionary] = [{
|
|
"id": 1,
|
|
"trigger": { "type": "entered_area", "source": 0, "target": area.get_instance_id(), "params": {} },
|
|
"actions": [],
|
|
}]
|
|
visuals.set_rules(rules_arr)
|
|
visuals._dirty = false
|
|
area.position += Vector2(120.0, -40.0)
|
|
var moved_area: Array[Node2D] = [area as Node2D]
|
|
stage._on_transform_committed(moved_area)
|
|
_check(visuals._dirty == true,
|
|
"_on_transform_committed marks director visuals dirty (TriggerArea move)")
|
|
|
|
stage.queue_free()
|
|
await process_frame
|
|
print("--------------------------------------------------------")
|
|
if _failures == 0:
|
|
print("RESULT: ALL PASSED (%d assertions, 0 failures)" % _checks)
|
|
quit(0)
|
|
else:
|
|
print("RESULT: %d FAILURE(S) out of %d assertions" % [_failures, _checks])
|
|
quit(1)
|
|
|
|
|
|
func _check(condition: bool, message: String) -> void:
|
|
_checks += 1
|
|
if condition:
|
|
print("PASS: " + message)
|
|
else:
|
|
_failures += 1
|
|
print("FAIL: " + message)
|