Files
TheTree_mock/tests/world/test_legacy_stairs.gd
T

214 lines
13 KiB
GDScript

extends SceneTree
const PathType = preload("res://scripts/world/path_service.gd")
const LegacyType = preload("res://scripts/world/legacy_stair_service.gd")
class ControlledPath:
extends PathService
var fail_restore_once := false
var fail_restore_always := false
var reenter: LegacyStairService
var nested_rejected := false
func restore_snapshot(snapshot: Dictionary) -> bool:
var result := super.restore_snapshot(snapshot)
if reenter != null:
var target := reenter
reenter = null
nested_rejected = not target.migrate_existing_vertical_walks()
if fail_restore_always:
set_vertical_walk_requires_connector(not get_vertical_walk_requires_connector())
return false
if fail_restore_once:
fail_restore_once = false
return false
return result
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
_test_one_time_migration_and_access()
_test_prune_and_no_regeneration()
_test_snapshot_ownership()
_test_atomic_failure_and_reentry()
print("Legacy stairs: %d checks, %d failures" % [_checks, _failures])
quit(_failures)
func _test_one_time_migration_and_access() -> void:
var path := PathType.new()
var cells: Array[Vector3i] = [Vector3i(0, 0, 0), Vector3i(0, 1, 0), Vector3i(0, 2, 0), Vector3i(1, 0, 0), Vector3i(1, 1, 0), Vector3i(2, 0, 0), Vector3i(2, 1, 0), Vector3i(0, 0, 1), Vector3i(0, 1, 1)]
_expect(path.rebuild_graph(cells), "materialize legacy floors")
_expect(path.configure_connector(&"staff.door", Vector3i(0, 0, 0), Vector3i(0, 0, 1), 120, true, &"staff"), "existing staff door remains separately owned")
_expect(path.configure_connector(&"external.express", Vector3i(0, 0, 0), Vector3i(0, 1, 0), 50, false, &"permit"), "existing cheaper one-way connector coexists with WALK")
var shaft_cells: Array[Vector3i] = [Vector3i(2, 0, 0), Vector3i(2, 1, 0)]
_expect(path.set_vertical_walk_blockers(&"infra.shaft:lift", shaft_cells), "existing elevator shaft suppresses ordinary climbing")
_expect(path.set_cell_temporary_block(Vector3i(1, 1, 0), true), "temporary traffic block does not remove structural connection")
_expect(path.project_occupancy([{&"actor_id": &"staff:porter", &"cell": Vector3i(0, 0, 1)}]), "preserve existing occupancy during migration")
var before := path.create_snapshot()
var legacy := LegacyType.new()
_expect(legacy.configure(path), "bind legacy owner")
_expect(legacy.migrate_existing_vertical_walks(), "one migration materializes ordinary vertical WALK edges")
var snapshot := legacy.create_snapshot()
_expect(snapshot[&"stairs"].size() == 4, "both FRONT and BACK WALK edges convert once, without shaft bypass")
_expect(path.get_vertical_walk_requires_connector() and legacy.validate_invariants()[&"ok"], "migration enables strict floor policy")
_expect(path.has_connector(&"legacy.stairs:0:0:0") and path.has_connector(&"legacy.stairs:0:0:1"), "stable IDs encode layer, x and lower floor")
_expect(not path.has_connector(&"legacy.stairs:0:2:0"), "shaft has no free compatibility stairs")
_expect(path.get_connector(&"legacy.stairs:0:1:0")[&"cost"] == 100, "temporary blocked route still migrates at original WALK score")
_expect(path.get_connector(&"legacy.stairs:1:0:0")[&"access_id"] == &"", "legacy BACK route keeps its previous access semantics")
_expect(path.get_connector(&"staff.door") == _connector(before, &"staff.door"), "staff door cost and permission are unchanged")
_expect(path.get_connector(&"external.express") == _connector(before, &"external.express"), "one-way custom connector retains exact configuration")
var after := path.create_snapshot()
for key: StringName in [&"cell_traffic", &"actor_cells", &"actor_progress", &"vertical_walk_blockers", &"active_elevator_units", &"known_elevator_request_ids", &"transit_actor_ids", &"traffic_revision"]:
_expect(after[key] == before[key], "migration preserves unrelated Path field %s" % key)
_expect(path.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0), [0], []).size() == 3, "ordinary guests retain their old multi-floor route")
_expect(path.find_path(Vector3i(0, 0, 0), Vector3i(0, 1, 1), [0, 1], []).is_empty(), "migration does not bypass staff-door access")
_expect(not path.find_path(Vector3i(0, 0, 0), Vector3i(0, 1, 1), [0, 1], [&"staff"]).is_empty(), "staff keep cross-layer commute via original door")
_expect(legacy.migrate_existing_vertical_walks() and legacy.create_snapshot() == snapshot and path.create_snapshot() == after, "repeat migration is an exact no-op")
cells.append(Vector3i(0, 3, 0))
_expect(path.rebuild_graph(cells), "append newly built upper corridor after migration")
_expect(legacy.migrate_existing_vertical_walks() and legacy.create_snapshot() == snapshot, "new vertical adjacency never receives compatibility stairs")
_expect(path.find_path(Vector3i(0, 2, 0), Vector3i(0, 3, 0)).is_empty(), "new floors require a real stair or elevator")
snapshot[&"stairs"].clear()
_expect(legacy.create_snapshot()[&"stairs"].size() == 4, "snapshot returns defensive metadata")
func _test_prune_and_no_regeneration() -> void:
var path := PathType.new()
var cells: Array[Vector3i] = [Vector3i(0, 0, 0), Vector3i(0, 1, 0), Vector3i(0, 2, 0), Vector3i(1, 0, 0), Vector3i(1, 1, 0)]
path.rebuild_graph(cells)
var legacy := LegacyType.new()
legacy.configure(path)
_expect(legacy.migrate_existing_vertical_walks(), "migrate prune fixture")
cells.erase(Vector3i(0, 1, 0))
_expect(path.rebuild_graph(cells), "demolish middle landing")
_expect(not legacy.validate_invariants()[&"ok"], "missing landing marks legacy ownership stale until prune")
_expect(legacy.prune_invalid(), "prune both incident stair edges atomically")
_expect(legacy.create_snapshot()[&"stairs"].size() == 1 and not path.has_connector(&"legacy.stairs:0:0:0") and not path.has_connector(&"legacy.stairs:0:0:1"), "removed landing retires both owned connector records")
cells.append(Vector3i(0, 1, 0))
_expect(path.rebuild_graph(cells) and legacy.prune_invalid(), "rebuild same coordinates after demolition")
_expect(path.find_path(Vector3i(0, 0, 0), Vector3i(0, 2, 0)).is_empty(), "retired links never resurrect at reused coordinates")
var blocked: Array[Vector3i] = [Vector3i(1, 1, 0)]
_expect(path.set_vertical_walk_blockers(&"new.shaft", blocked), "new elevator shaft covers remaining landing")
_expect(legacy.prune_invalid() and legacy.create_snapshot()[&"stairs"].is_empty(), "new shaft removes touching compatibility connector")
_expect(path.remove_vertical_walk_blockers(&"new.shaft") and legacy.prune_invalid(), "remove elevator shaft later")
_expect(not path.has_connector(&"legacy.stairs:0:1:0"), "removing a shaft does not restore compatibility stairs")
var before := path.create_snapshot()
_expect(legacy.prune_invalid() and path.create_snapshot() == before, "unchanged prune does not advance graph revision")
path.set_vertical_walk_requires_connector(false)
before = path.create_snapshot()
_expect(not legacy.migrate_existing_vertical_walks() and not legacy.prune_invalid(), "policy tampering cannot restart closed migration")
_expect(path.create_snapshot() == before, "rejected repeated migration does not mutate tampered Path")
func _test_snapshot_ownership() -> void:
var path := PathType.new()
var cells: Array[Vector3i] = [Vector3i(-1, -1, 0), Vector3i(-1, 0, 0), Vector3i(2, 0, 1), Vector3i(2, 1, 1)]
path.rebuild_graph(cells)
var legacy := LegacyType.new()
legacy.configure(path)
_expect(legacy.migrate_existing_vertical_walks(), "migrate negative floor and BACK snapshot fixture")
var saved_path := path.create_snapshot()
var saved := legacy.create_snapshot()
var restored_path := PathType.new()
var restored := LegacyType.new()
_expect(restored.configure(restored_path), "bind destination before restoring Path")
_expect(restored_path.restore_snapshot(saved_path) and restored_path.rebuild_graph(cells), "restore and materialize saved Path")
_expect(restored.restore_snapshot(saved) and restored.create_snapshot() == saved, "strict current legacy snapshot roundtrip")
var malformed: Array[Dictionary] = []
var row := saved.duplicate(true)
row[&"extra"] = true
malformed.append(row)
row = saved.duplicate(true)
row[&"schema_version"] = 2
malformed.append(row)
row = saved.duplicate(true)
row[&"schema_version"] = "1"
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"].reverse()
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"].append(row[&"stairs"][0].duplicate(true))
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"][0][&"id"] = "legacy.stairs:forged"
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"][0][&"to"] = Vector3i(-1, 1, 0)
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"][0][&"to"] = Vector3i(-1, 0, 1)
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"][0][&"cost"] = 100
malformed.append(row)
row = saved.duplicate(true)
row[&"stairs"].clear()
malformed.append(row)
for bad: Dictionary in malformed:
_expect(not restored.restore_snapshot(bad), "reject malformed or incomplete compatibility ownership")
_expect(restored.create_snapshot() == saved and restored_path.create_snapshot() == saved_path, "legacy snapshot rejection preserves metadata and Path exactly")
restored_path.configure_connector(&"legacy.stairs:orphan", cells[0], cells[1])
_expect(not restored.restore_snapshot(saved) and not restored.prune_invalid(), "untracked managed connector blocks restore and prune")
restored_path.remove_connector(&"legacy.stairs:orphan")
restored_path.configure_connector(&"legacy.stairs:0:-1:-1", cells[0], cells[1], 100, true, &"staff")
_expect(not restored.restore_snapshot(saved) and not restored.prune_invalid(), "owned connector permission tampering is rejected")
_expect(restored_path.restore_snapshot(saved_path), "repair exact connector configuration")
restored_path.set_vertical_walk_requires_connector(false)
_expect(not restored.restore_snapshot(saved), "current legacy snapshot cannot restore with free vertical walking")
var fresh_path := PathType.new()
fresh_path.rebuild_graph(cells)
fresh_path.set_vertical_walk_requires_connector(true)
var fresh := LegacyType.new()
fresh.configure(fresh_path)
_expect(fresh.migrate_existing_vertical_walks() and fresh.create_snapshot()[&"stairs"].is_empty(), "new strict game never gains migration stairs")
_expect(fresh.restore_snapshot({&"schema_version": 1, &"stairs": []}), "new game empty legacy snapshot is valid")
var out_of_bounds_path := PathType.new()
out_of_bounds_path.rebuild_graph([Vector3i(100_001, 0, 0), Vector3i(100_001, 1, 0)])
var out_of_bounds := LegacyType.new()
out_of_bounds.configure(out_of_bounds_path)
var out_of_bounds_before := out_of_bounds_path.create_snapshot()
_expect(not out_of_bounds.migrate_existing_vertical_walks() and out_of_bounds_path.create_snapshot() == out_of_bounds_before, "unsupported migration coordinates cannot create unrestorable records")
func _test_atomic_failure_and_reentry() -> void:
var path := ControlledPath.new()
var cells: Array[Vector3i] = [Vector3i(0, 0, 0), Vector3i(0, 1, 0), Vector3i(0, 2, 0)]
path.rebuild_graph(cells)
var legacy := LegacyType.new()
legacy.configure(path)
var before := path.create_snapshot()
var metadata := legacy.create_snapshot()
path.fail_restore_once = true
_expect(not legacy.migrate_existing_vertical_walks(), "injected partial Path apply failure rejects migration")
_expect(path.create_snapshot() == before and legacy.create_snapshot() == metadata, "failed migration restores Path and owned metadata exactly")
path.reenter = legacy
_expect(legacy.migrate_existing_vertical_walks() and path.nested_rejected, "outer migration succeeds while nested migration is rejected")
cells.erase(Vector3i(0, 1, 0))
path.rebuild_graph(cells)
before = path.create_snapshot()
metadata = legacy.create_snapshot()
path.fail_restore_once = true
_expect(not legacy.prune_invalid(), "injected partial prune failure rejects ownership removal")
_expect(path.create_snapshot() == before and legacy.create_snapshot() == metadata, "failed prune restores both dangling records and original Path for caller rollback")
_expect(legacy.prune_invalid(), "prune can retry after exact rollback")
var broken_path := ControlledPath.new()
broken_path.rebuild_graph([Vector3i(0, 0, 0), Vector3i(0, 1, 0)])
var broken := LegacyType.new()
broken.configure(broken_path)
broken_path.fail_restore_always = true
_expect(not broken.migrate_existing_vertical_walks(), "repeated rollback failure rejects migration")
_expect(broken.validate_invariants()[&"quarantined"] and not broken.migrate_existing_vertical_walks(), "uncertain rollback quarantines future mutation")
func _connector(snapshot: Dictionary, connector_id: StringName) -> Dictionary:
for connector: Dictionary in snapshot[&"connectors"]:
if StringName(connector[&"id"]) == connector_id:
return connector
return {}
func _expect(ok: bool, label: String) -> void:
_checks += 1
if not ok:
_failures += 1
push_error(label)