Files
TheTree_mock/tests/world/test_path_vertical_policy.gd

106 lines
6.8 KiB
GDScript

extends SceneTree
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
_test_policy_and_connectors()
_test_recovery_and_diagnostics()
_test_snapshots()
print("Path vertical policy: %d checks, %d failures" % [_checks, _failures])
quit(_failures)
func _path() -> PathService:
var path := PathService.new()
path.rebuild_graph([Vector3i.ZERO, Vector3i(1, 0, 0), Vector3i(0, 1, 0), Vector3i(1, 1, 0), Vector3i(0, 0, 1), Vector3i(0, 1, 1)])
return path
func _test_policy_and_connectors() -> void:
var path := _path()
var bottom := Vector3i.ZERO
var top := Vector3i(0, 1, 0)
_expect(not path.get_vertical_walk_requires_connector(), "standalone Path retains legacy cardinal movement by default")
var old_route := path.find_path(bottom, top)
_expect(old_route == [bottom, top] and path.cached_path_count() == 1, "legacy upper-floor route can be cached")
var graph_before := path.graph_revision
_expect(path.set_vertical_walk_requires_connector(true), "strict vertical policy enables")
_expect(path.graph_revision == graph_before + 1 and path.cached_path_count() == 0, "policy change invalidates previously cached floor climbing")
_expect(path.find_path(bottom, top).is_empty() and path.last_no_route_reason == PathService.ROUTE_GOAL_UNREACHABLE, "adjacent floors require an explicit vertical connection")
_expect(path.calculate_path_cost(old_route) == -1 and path.get_edge_report(bottom, top).is_empty(), "cost and movement edge resolution cannot bypass strict routing")
_expect(path.find_path(bottom, Vector3i(1, 0, 0)).size() == 2, "horizontal walking remains available")
var raw_vertical := false
for edge: Dictionary in path.get_neighbors(bottom):
if edge[&"to"] == top and edge[&"movement_type"] == PathService.MOVEMENT_WALK: raw_vertical = true
_expect(raw_vertical, "raw structural neighbors remain available to legacy-stair migration")
var snapshot := path.create_snapshot()
_expect(path.set_vertical_walk_requires_connector(true) and path.create_snapshot() == snapshot, "reapplying the same policy is an exact no-op")
_expect(path.configure_connector(&"stairs", bottom, top, 150), "explicit public stairs register")
_expect(path.find_path(bottom, top) == [bottom, top] and path.get_step_connector(bottom, top) == &"stairs", "explicit stairs work through strict policy")
_expect(path.calculate_path_cost([bottom, top]) == 150, "stairs keep their defined movement cost")
path.set_connector_enabled(&"stairs", false)
_expect(path.find_path(bottom, top).is_empty() and path.last_no_route_reason == PathService.ROUTE_CONNECTOR_UNAVAILABLE, "closed stairs cannot fall back to implicit floor climbing")
path.configure_connector(&"service_stairs", Vector3i(0, 0, 1), Vector3i(0, 1, 1), 150, true, &"staff")
_expect(path.find_path(Vector3i(0, 0, 1), Vector3i(0, 1, 1), [1], []).is_empty(), "service stairs retain staff-only access")
_expect(path.find_path(Vector3i(0, 0, 1), Vector3i(0, 1, 1), [1], [&"staff"]).size() == 2, "authorized staff use explicit BACK stairs")
path.configure_elevator(&"lift", bottom, top)
_expect(path.get_step_connector(bottom, top) == &"lift", "an operational elevator remains an explicit vertical route")
path.set_connector_enabled(&"lift", false)
_expect(path.find_path(bottom, top).is_empty(), "a stopped lift never exposes an ordinary vertical edge")
path.set_vertical_walk_blockers(&"shaft", [bottom, top])
path.set_vertical_walk_requires_connector(false)
_expect(path.get_edge_report(bottom, top).is_empty(), "physical shaft blockers survive opting out of the global floor policy")
func _test_recovery_and_diagnostics() -> void:
var path := PathService.new()
var bottom := Vector3i.ZERO
var top := Vector3i(0, 1, 0)
path.rebuild_graph([bottom, top])
path.set_vertical_walk_requires_connector(true)
path.set_cell_temporary_block(bottom, true)
_expect(not path.find_nearest_walkable_recovery(bottom).get(&"found", false), "recovery cannot choose an unreachable floor solely because it is nearby")
path.configure_connector(&"stairs", bottom, top, 150)
_expect(path.find_nearest_walkable_recovery(bottom).get(&"cell") == top, "a real public stair makes the upper recovery proposal structurally reachable")
path.set_connector_enabled(&"stairs", false)
_expect(not path.find_nearest_walkable_recovery(bottom).get(&"found", false), "recovery respects an unavailable vertical connector")
path.set_cell_temporary_block(bottom, false)
path.remove_connector(&"stairs")
path.rebuild_graph([bottom, top, Vector3i(1, 0, 0), Vector3i(1, 1, 0)])
path.set_cell_temporary_block(Vector3i(1, 0, 0), true)
_expect(path.find_path(bottom, top).is_empty() and path.last_no_route_reason == PathService.ROUTE_GOAL_UNREACHABLE, "diagnostics do not invent a blocked walking route between floors")
path.set_vertical_walk_requires_connector(false)
_expect(path.find_path(bottom, top) == [bottom, top], "explicit legacy opt-out restores standalone vertical walking")
func _test_snapshots() -> void:
var path := _path()
path.set_vertical_walk_requires_connector(true)
path.set_vertical_walk_blockers(&"shaft", [Vector3i.ZERO, Vector3i(0, 1, 0)])
var saved := path.create_snapshot()
_expect(saved[&"schema_version"] == 5 and saved[&"vertical_walk_requires_connector"] == true and saved[&"transit_actor_ids"] == [], "Path v5 saves explicit policy and transit occupancy")
var restored := _path()
_expect(restored.restore_snapshot(saved) and restored.create_snapshot() == saved, "strict policy and shaft ownership restore exactly")
for value: Variant in [0, 1, "true", null]:
var bad := saved.duplicate(true)
bad[&"vertical_walk_requires_connector"] = value
_expect(not restored.restore_snapshot(bad) and restored.create_snapshot() == saved, "non-bool vertical policy rejects atomically: %s" % str(value))
var missing := saved.duplicate(true)
missing.erase(&"vertical_walk_requires_connector")
_expect(not restored.restore_snapshot(missing), "v5 cannot silently default a missing policy")
var legacy := saved.duplicate(true)
legacy[&"schema_version"] = 4
_expect(not restored.restore_snapshot(legacy), "outer-only legacy downgrade cannot hide new policy fields")
legacy.erase(&"vertical_walk_requires_connector")
legacy.erase(&"transit_actor_ids")
_expect(restored.restore_snapshot(legacy) and not restored.get_vertical_walk_requires_connector(), "v4 defaults to its original vertical rules for Runtime-managed migration")
_expect(restored.get_vertical_walk_blockers() == path.get_vertical_walk_blockers(), "v4 keeps existing shaft ownership independently of v5 policy")
var migrated := restored.create_snapshot()
_expect(restored.restore_snapshot(migrated) and restored.create_snapshot() == migrated, "legacy migration is canonical and does not repeat on second restore")
func _expect(ok: bool, label: String) -> void:
_checks += 1
if not ok:
_failures += 1
push_error(label)