Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
81 lines
5.9 KiB
GDScript
81 lines
5.9 KiB
GDScript
extends SceneTree
|
|
var checks := 0
|
|
var failures := 0
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
func expect(ok: bool, message: String) -> void:
|
|
checks += 1
|
|
if not ok:
|
|
failures += 1
|
|
push_error(message)
|
|
func _run() -> void:
|
|
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
|
|
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
|
var state: Variant = load("res://autoload/game_state.gd").new()
|
|
clock.reset(1, 6, 0)
|
|
state.reset()
|
|
expect(runtime.initialize(clock, state, 424242)[&"valid"], "initialize")
|
|
clock.set_paused(true)
|
|
expect(runtime.enable_production_operations()[&"ok"], "enable")
|
|
var definition: FacilityDefinition = runtime.definition_registry.get_facility(&"guest_corridor")
|
|
var old_rate := definition.maintenance_gold
|
|
definition.maintenance_gold = 1440
|
|
expect(runtime.submit_command(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(4, 1, 0)}).is_success(), "build completed asset")
|
|
runtime.operations_coordinator._legacy_calendar_last_day = 1
|
|
clock.advance_minutes(1079)
|
|
var legacy: Dictionary = runtime.create_snapshot()
|
|
var data: Dictionary = legacy[&"systems"][&"runtime"]
|
|
data[&"runtime_schema_version"] = 9
|
|
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(data)
|
|
data[&"operations"][&"coordinator"][&"schema_version"] = 3
|
|
data[&"operations"][&"coordinator"].erase(&"legacy_calendar_last_day")
|
|
data[&"operations"][&"coordinator"].erase(&"legacy_history_last_day")
|
|
data[&"operations"][&"coordinator"].erase(&"legacy_principal_profit_last_day")
|
|
expect(runtime.restore_snapshot(legacy), "constructed v9/v3 calendar fixture migrates before midnight")
|
|
var ledger_before: Dictionary = runtime.economy_service.create_snapshot()
|
|
runtime.set_operations_test_boundary_hook(&"MIDNIGHT_UPKEEP", func(_payload: Dictionary, phase: StringName, _token: Variant) -> Dictionary:
|
|
return {&"ok": phase != runtime.OPERATIONS_TEST_AFTER_FIRST_MUTATION_PHASE})
|
|
clock.advance_minutes(1)
|
|
expect(runtime.get_operations_report()[&"runtime_failure_latched"] and clock.absolute_minute == 1440, "midnight failure pauses before legacy financial close")
|
|
expect(runtime.economy_service.create_snapshot() == ledger_before and runtime.upkeep_settlement.get_settled_period_count() == 0, "midnight rollback restores cash ledger and receipt atomically")
|
|
var failed: Dictionary = runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(failed), "failed midnight checkpoint restores")
|
|
runtime.set_operations_test_boundary_hook(&"MIDNIGHT_UPKEEP", Callable())
|
|
expect(runtime.acknowledge_operations_pause()[&"ok"], "same midnight retries through existing acknowledgement")
|
|
expect(runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1 and runtime.upkeep_settlement.get_settled_period_count() == 1, "only post-migration minute settles at midnight")
|
|
expect(runtime.operations_coordinator.get_day_summaries().is_empty(), "legacy payroll and financial day are not rewritten")
|
|
var midnight: Dictionary = runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(midnight) and runtime.create_snapshot() == midnight, "midnight interim payment roundtrips exactly")
|
|
clock.advance_minutes(360)
|
|
var summary: Dictionary = runtime.operations_coordinator.get_day_summary(1)
|
|
expect(not summary.is_empty() and summary[&"closed_at"] == 1800, "legacy financial close remains at 06:00")
|
|
if not summary.is_empty():
|
|
expect(summary[&"category_totals"][&"maintenance"] == 1 and runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1, "06:00 reports midnight expense without a second charge")
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()), "06:00 history and earlier midnight receipt reconcile on load")
|
|
# A later failure must retain the already committed midnight payment exactly once.
|
|
expect(runtime.restore_snapshot(legacy), "restore before later-boundary failure")
|
|
runtime.set_operations_test_boundary_hook(&"ARRIVAL_PLAN", func(_payload: Dictionary, phase: StringName, _token: Variant) -> Dictionary:
|
|
return {&"ok": phase != runtime.OPERATIONS_TEST_PREPARE_PHASE})
|
|
clock.advance_minutes(1)
|
|
expect(runtime.get_operations_report()[&"runtime_failure_latched"] and runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1, "later failure preserves committed midnight payment")
|
|
var after_payment_failure: Dictionary = runtime.create_snapshot()
|
|
expect(runtime.restore_snapshot(after_payment_failure), "save distinguishes committed payment from pending later boundary")
|
|
runtime.set_operations_test_boundary_hook(&"ARRIVAL_PLAN", Callable())
|
|
expect(runtime.acknowledge_operations_pause()[&"ok"] and runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1 and runtime.upkeep_settlement.get_settled_period_count() == 1, "retry never duplicates earlier midnight payment")
|
|
# New interim debt blocks spending immediately, without rewriting old summaries.
|
|
expect(runtime.restore_snapshot(legacy), "restore legacy insufficient-cash branch")
|
|
var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
|
|
expect(runtime.economy_service.transfer(&"PLAYER_CASH", &"CONSTRUCTION_EXPENSE", cash, 1439, &"CONSTRUCTION").is_success(), "deplete cash")
|
|
clock.advance_minutes(1)
|
|
expect(runtime.get_operations_report()[&"arrears_total"] == 1 and runtime.operations_coordinator.get_arrears_total() == 0, "live debt is visible while closed financial history stays unchanged")
|
|
clock.set_paused(true)
|
|
var blocked: CommandResult = runtime.submit_command(&"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(5, 1, 0)})
|
|
expect(not blocked.is_success() and blocked.details.get(&"reason") == &"UNPAID_EXPENSES", "interim upkeep debt blocks new investment at midnight")
|
|
expect(runtime.restore_snapshot(runtime.create_snapshot()), "interim debt saves and restores without a synthetic daily summary")
|
|
definition.maintenance_gold = old_rate
|
|
runtime.free()
|
|
clock.free()
|
|
state.free()
|
|
print("%s: %d checks" % ["PASS" if failures == 0 else "FAIL", checks])
|
|
quit(failures)
|