Files
TheTree_mock/tests/transport/test_transport_save.gd

158 lines
9.6 KiB
GDScript

extends SceneTree
var _checks := 0
var _failures := 0
var _serial := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var fixture := _fixture(81423)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
clock.advance_minutes(3)
var current: Dictionary = runtime.create_snapshot()
_expect(current[&"systems"][&"runtime"][&"runtime_schema_version"] == 14, "Runtime emits schema14 with elevator and explicit vertical-route aggregates")
var legacy := current.duplicate(true)
var data: Dictionary = legacy[&"systems"][&"runtime"]
data[&"runtime_schema_version"] = 7
data.erase(&"elevators")
data.erase(&"legacy_stairs")
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(data)
data[&"path"][&"schema_version"] = 3
data[&"path"].erase(&"vertical_walk_blockers")
data[&"path"].erase(&"vertical_walk_requires_connector")
data[&"path"].erase(&"transit_actor_ids")
_expect(runtime.restore_snapshot(legacy), "genuine v7 without lifts migrates from Path3 into Runtime9")
var migrated: Dictionary = runtime.create_snapshot()
var expected := current.duplicate(true)
expected[&"systems"][&"runtime"][&"facility_upkeep"] = preload("res://tests/fixtures/pre_upkeep_runtime.gd").migrated_accrual(clock.absolute_minute)
expected[&"systems"][&"runtime"][&"weather"] = preload("res://tests/fixtures/pre_upkeep_runtime.gd").migrated_weather(clock.absolute_minute)
# Closing the old implicit-WALK topology bumps only the Path graph revision.
expected[&"systems"][&"runtime"][&"path"][&"graph_revision"] += 1
_expect(migrated == expected, "empty-lift migration preserves all state except the explicit topology revision")
var bad := current.duplicate(true)
bad[&"systems"][&"runtime"][&"runtime_schema_version"] = 7
_expect(_rejects(runtime, bad), "outer-only downgrade retaining elevator state is rejected atomically")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"].erase(&"elevators")
_expect(_rejects(runtime, bad), "Runtime9 cannot omit elevator aggregate")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"elevators"][&"current_minute"] -= 1
_expect(_rejects(runtime, bad), "elevator clock must match Runtime domain minute")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"path"][&"schema_version"] = 3
_expect(_rejects(runtime, bad), "Path3 relabel with retained vertical blocker metadata is rejected")
_expect(_command(runtime, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(0, 0, 0)}).is_success(), "real construction starts elevator module")
clock.advance_minutes(310)
_expect(_command(runtime, clock, &"hire_staff_candidate", {&"candidate_id": &"staff_akane"}).is_success(), "hire actual actor at entrance for ownership fixture")
var worker: StaffRuntime = runtime.staff_service.get_staff(&"staff_akane")
var actor_id := &"staff:staff_akane"
_expect(worker != null and worker.current_cell == Vector3i.ZERO, "hired actor is physically at elevator's ground landing")
var access: Array[StringName] = [&"staff"]
var queued: Dictionary = runtime.elevators.request_trip(actor_id, Vector3i.ZERO, Vector3i(0, 1, 0), clock.absolute_minute, access)
_expect(queued.get(&"ok", false), "queue real actor through transport ownership API: %s" % queued)
if not queued.get(&"ok", false):
for key: StringName in [&"runtime", &"clock", &"state"]: fixture[key].free()
quit(1)
return
clock.advance_minutes(1)
var trip: Dictionary = runtime.elevators.get_actor_trip(actor_id)
_expect(trip.get(&"state") == PathService.ELEVATOR_REQUEST_BOARDED, "save fixture owns a physical cabin seat")
current = runtime.create_snapshot()
_expect(runtime.restore_snapshot(current), "Runtime9 restores actual cabin actor and projected origin crosslinks")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"elevators"][&"trips"][0][&"actor_id"] = &"staff:missing_person"
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"boarded"][0] = &"staff:missing_person"
for unit: Dictionary in bad[&"systems"][&"runtime"][&"path"][&"active_elevator_units"]:
if unit[&"unit_id"] == actor_id: unit[&"unit_id"] = &"staff:missing_person"
_expect(_rejects(runtime, bad), "internally consistent seat and Path owner cannot refer to nonexistent Runtime actor")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"config"][&"module_ids"][0] = &"missing_module"
_expect(_rejects(runtime, bad), "elevator cabin cannot substitute a module absent from real construction")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"boarded"] = []
_expect(_rejects(runtime, bad), "active Path rider cannot lose its cabin seat")
bad = current.duplicate(true)
bad[&"systems"][&"runtime"][&"elevators"][&"trips"][0][&"from"] = Vector3i(0, 1, 0)
bad[&"systems"][&"runtime"][&"elevators"][&"trips"][0][&"to"] = Vector3i.ZERO
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"boarding_floor"] = 1
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"target_floor"] = 0
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"current_floor"] = 1
bad[&"systems"][&"runtime"][&"elevators"][&"shafts"][0][&"phase_origin_floor"] = 1
_expect(_rejects(runtime, bad), "valid reverse cabin route cannot move actor's saved logical origin")
var shaft_id: StringName = runtime.elevators.get_report()[&"shafts"][0][&"shaft_id"]
_expect(_command(runtime, clock, &"set_elevator_operation", {&"shaft_id": shaft_id, &"operator_open": false}).is_success(), "player closes running elevator through public command")
current = runtime.create_snapshot()
_expect(runtime.restore_snapshot(current) and not runtime.elevators.get_report()[&"shafts"][0][&"operator_open"], "closed operator policy survives Runtime restore")
for key: StringName in [&"runtime", &"clock", &"state"]: fixture[key].free()
_test_attendance_migration()
print("Transport save: %d checks, %d failures" % [_checks, _failures])
quit(0 if _failures == 0 else 1)
func _test_attendance_migration() -> void:
var fixture := _fixture(81424)
var runtime: Variant = fixture[&"runtime"]
var clock: Variant = fixture[&"clock"]
_expect(_command(runtime, clock, &"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(2, 0, 0)}).is_success(), "attendance fixture builds a real workplace")
clock.advance_minutes(180)
var facility: FacilityInstance = runtime.facility_service.get_instances()[0]
_expect(_command(runtime, clock, &"hire_staff_candidate", {&"candidate_id": &"staff_akane"}).is_success(), "attendance fixture hires actual receptionist")
_expect(_command(runtime, clock, &"set_staff_work_assignment", {&"staff_id": &"staff_akane", &"facility_id": facility.instance_id, &"template_id": &"DAY"}).is_success(), "attendance fixture assigns a real shift")
var worker: StaffRuntime = runtime.staff_service.get_staff(&"staff_akane")
_expect(not StaffCommuteService.is_at_facility(worker, facility), "employee has not yet physically walked to reception")
# Reproduce the old logical-attendance rule without changing position, route,
# income or inventory. Facility projection is rebuilt by its public service.
worker.state = StaffRuntime.State.AVAILABLE
runtime.facility_service.set_operational_status(facility.instance_id, {&"active_staff_ids": [&"staff_akane"]}, clock.absolute_minute)
var logical: Dictionary = runtime.create_snapshot()
_expect(_rejects(runtime, logical), "Runtime9 rejects an AVAILABLE employee counted at a distant workplace")
var legacy := logical.duplicate(true)
var data: Dictionary = legacy[&"systems"][&"runtime"]
data[&"runtime_schema_version"] = 7
data.erase(&"elevators")
data.erase(&"legacy_stairs")
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(data)
data[&"path"][&"schema_version"] = 3
data[&"path"].erase(&"vertical_walk_blockers")
data[&"path"].erase(&"vertical_walk_requires_connector")
data[&"path"].erase(&"transit_actor_ids")
_expect(runtime.restore_snapshot(legacy), "genuine v7 logical attendance migrates into physical attendance")
facility = runtime.facility_service.get_instance(facility.instance_id)
worker = runtime.staff_service.get_staff(&"staff_akane")
_expect(facility.active_staff_ids.is_empty() and worker.state == StaffRuntime.State.COMMUTING and worker.current_cell == Vector3i.ZERO, "migration removes phantom workplace capacity and starts commute without teleporting")
_expect(runtime.restore_snapshot(runtime.create_snapshot()), "migrated attendance is a valid current Runtime snapshot")
for key: StringName in [&"runtime", &"clock", &"state"]: fixture[key].free()
func _fixture(seed: int) -> Dictionary:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0)
state.reset()
_expect(runtime.initialize(clock, state, seed)[&"valid"], "transport save fixture initializes")
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
clock.set_paused(true)
return {&"clock": clock, &"state": state, &"runtime": runtime}
func _command(runtime: Variant, clock: Variant, kind: StringName, payload: Dictionary) -> CommandResult:
_serial += 1
return runtime.submit_command(kind, payload, &"player", &"", 0, clock.absolute_minute, StringName("transport.save.%d" % _serial))
func _rejects(runtime: Variant, candidate: Dictionary) -> bool:
var before: Dictionary = runtime.create_snapshot()
return not runtime.restore_snapshot(candidate) and runtime.create_snapshot() == before
func _expect(condition: bool, label: String) -> void:
_checks += 1
if not condition: _failures += 1
print("%s: %s" % ["PASS" if condition else "FAIL", label])