Files
TheTree_mock/tests/s2/test_mana_reserve_new_pid.gd
T

112 lines
4.6 KiB
GDScript

extends SceneTree
## A06 reserve across a real process boundary. Run "-- writer" first, then
## "-- reader" in a new Godot process; the reader must reproduce the writer's
## continuation exactly from the disk save, and migrate a legacy save.
const Cycle = preload("res://scripts/mana/mana_reserve_cycle.gd")
const CURRENT_SAVE := "user://saves/a06_mana_new_pid_current"
const LEGACY_SAVE := "user://saves/a06_mana_new_pid_legacy"
const EXPECTED_PATH := "user://saves/a06_mana_new_pid_expected.json"
const CONTINUE_MINUTES := 75
var _checks := 0
var _failures := 0
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var mode := "writer" if not "reader" in OS.get_cmdline_user_args() else "reader"
print("S2: A06 Mana reserve new-PID %s (pid %d)" % [mode, OS.get_process_id()])
if mode == "writer":
_write()
else:
_read()
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
quit(_failures)
func _new_runtime() -> Array:
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()
runtime.initialize(clock, state, 4404)
clock.set_paused(true)
return [clock, state, runtime]
func _free(nodes: Array) -> void:
for node: Variant in nodes:
node.free()
func _write() -> void:
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
# Stop mid-interval so the reader must not settle the pending boundary early.
clock.advance_minutes(43)
var snapshot: Dictionary = runtime.create_snapshot()
_expect(SaveService.save_snapshot(CURRENT_SAVE, snapshot)[&"ok"], "writer saves current A06 reserve")
var legacy: Dictionary = snapshot.duplicate(true)
legacy[&"systems"][&"runtime"].erase(&"mana_reserve")
legacy[&"game_state"][&"resources"][&"mana"] = 0
_expect(SaveService.save_snapshot(LEGACY_SAVE, legacy)[&"ok"], "writer saves legacy zero-reserve save")
var saved_mana: int = state.get_resource(&"mana")
clock.advance_minutes(CONTINUE_MINUTES)
var expected := {
"writer_pid": OS.get_process_id(),
"saved_minute": int(snapshot[&"clock"][&"absolute_minute"]),
"saved_mana": saved_mana,
"mana": state.get_resource(&"mana"),
"reserve": var_to_str(runtime.mana_reserve.create_snapshot()),
"digest": SimulationDigest.compute(runtime.create_snapshot()),
}
var file := FileAccess.open(EXPECTED_PATH, FileAccess.WRITE)
_expect(file != null, "writer records continuation")
if file != null:
file.store_string(JSON.stringify(expected))
file.close()
_free(nodes)
func _read() -> void:
var expected: Variant = JSON.parse_string(FileAccess.get_file_as_string(EXPECTED_PATH))
_expect(expected is Dictionary, "reader finds writer record")
if not expected is Dictionary:
return
_expect(int(expected["writer_pid"]) != OS.get_process_id(), "reader runs in a different process")
var nodes := _new_runtime()
var clock: Variant = nodes[0]
var state: Variant = nodes[1]
var runtime: Variant = nodes[2]
var loaded := SaveService.load_snapshot(CURRENT_SAVE)
_expect(loaded[&"ok"] and runtime.restore_snapshot(loaded[&"snapshot"]), "reader restores current save from disk")
_expect(clock.absolute_minute == int(expected["saved_minute"]) and state.get_resource(&"mana") == int(expected["saved_mana"]), "restored minute and reserve match the save")
clock.advance_minutes(CONTINUE_MINUTES)
_expect(state.get_resource(&"mana") == int(expected["mana"]), "continued reserve matches the writer")
_expect(var_to_str(runtime.mana_reserve.create_snapshot()) == String(expected["reserve"]), "continued reserve receipt matches the writer")
_expect(SimulationDigest.compute(runtime.create_snapshot()) == String(expected["digest"]), "whole continued state digest matches the writer")
var legacy := SaveService.load_snapshot(LEGACY_SAVE)
_expect(legacy[&"ok"] and runtime.restore_snapshot(legacy[&"snapshot"]), "reader migrates legacy save from disk")
_expect(state.get_resource(&"mana") == 0 and runtime.mana_reserve.get_last_flow().is_empty(), "legacy explicit 0 stays stopped")
_expect(runtime.create_snapshot()[&"systems"][&"runtime"].has(&"mana_reserve"), "migrated state saves with the A06 reserve")
for path: String in [CURRENT_SAVE, LEGACY_SAVE]:
SaveService.delete_save(path)
DirAccess.remove_absolute(ProjectSettings.globalize_path(EXPECTED_PATH))
_free(nodes)
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
else:
_failures += 1
push_error(" ✗ %s" % label)