Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
90 lines
5.1 KiB
GDScript
90 lines
5.1 KiB
GDScript
extends SceneTree
|
|
|
|
const Accrual = preload("res://scripts/economy/facility_upkeep_accrual.gd")
|
|
var checks := 0
|
|
var failures := 0
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_run")
|
|
|
|
func expect(value: bool, label: String) -> void:
|
|
checks += 1
|
|
if not value:
|
|
failures += 1
|
|
push_error(label)
|
|
|
|
func _run() -> void:
|
|
var service := Accrual.new()
|
|
expect(not service.advance_to(1, {}).ok, "an explicit starting minute is required; no retroactive fees")
|
|
expect(service.start_at(360).ok, "start at actual migration/start time")
|
|
expect(not service.start_at(0).ok, "starting twice cannot wipe accumulated charges")
|
|
service.advance_to(720, {&"room": 24, &"empty": 0})
|
|
expect(service.get_report().pending_facility_units == {"room": 8640}, "six hours at 24/day accrues exactly six gold")
|
|
service.advance_to(1080, {&"room": 24, &"new_room": 48})
|
|
var checkpoint := service.create_snapshot()
|
|
var restored := Accrual.new()
|
|
expect(restored.restore_snapshot(checkpoint), "partial day can be restored")
|
|
# The absent room has been demolished; its already accrued expense remains.
|
|
var close := service.advance_to(1440, {&"new_room": 48})
|
|
restored.advance_to(1440, {&"new_room": 48})
|
|
expect(close.closed_periods.size() == 1, "00:00 closes exactly one period")
|
|
var period: Dictionary = close.closed_periods[0]
|
|
expect(period.period_start == 360 and period.period_end == 1440, "first partial day never bills time before initialization")
|
|
expect(period.facility_units == {"new_room": 34560, "room": 17280}, "demolition stops future accrual but preserves incurred costs")
|
|
expect(service.create_snapshot() == restored.create_snapshot(), "save/load preserves exact fractional accumulation")
|
|
var before := service.create_snapshot()
|
|
expect(service.advance_to(1440, {&"new_room": 48}).ok and service.create_snapshot() == before, "same-minute replay cannot charge twice")
|
|
expect(not service.advance_to(1439, {}).ok and service.create_snapshot() == before, "rewind rejected without mutation")
|
|
close.closed_periods[0].facility_units.room = 999
|
|
expect(service.create_snapshot() == before, "returned period cannot mutate authoritative accrual")
|
|
var report := service.get_report()
|
|
report.closed_periods.clear()
|
|
expect(service.create_snapshot() == before, "report is a detached copy")
|
|
for rates: Dictionary in [{"bad": -1}, {"bad": 0.5}, {"bad": true}, {"": 1}, {"bad": Accrual.MAX_DAILY_RATE + 1}, {1: 5}]:
|
|
expect(not service.advance_to(1441, rates).ok and service.create_snapshot() == before, "invalid rates reject atomically: %s" % str(rates))
|
|
expect(not service.advance_to(2881, {}).ok and service.create_snapshot() == before, "unbounded batch rejected")
|
|
# Integer numerator is retained; neither per-minute nor per-day truncation.
|
|
var fractional := Accrual.new()
|
|
fractional.start_at(1439)
|
|
fractional.advance_to(1441, {"one_gold_per_day": 1})
|
|
var fraction_report := fractional.get_report()
|
|
expect(fraction_report.closed_periods[0].facility_units.one_gold_per_day == 1, "one minute charge is not rounded to zero")
|
|
expect(fraction_report.pending_facility_units.one_gold_per_day == 1, "midnight split conserves the second minute")
|
|
expect(fraction_report.gold_denominator == 1440, "settlement receives exact monetary unit denominator")
|
|
var split := Accrual.new()
|
|
var batched := Accrual.new()
|
|
split.start_at(0)
|
|
batched.start_at(0)
|
|
for minute in range(1, 1441):
|
|
split.advance_to(minute, {"b": 17, "a": 5})
|
|
batched.advance_to(1440, {"a": 5, "b": 17})
|
|
expect(split.create_snapshot() == batched.create_snapshot(), "input order and batching cannot change charges")
|
|
var json_copy: Dictionary = JSON.parse_string(JSON.stringify(split.create_snapshot()))
|
|
# JSON.parse_string produces floats; the project's snapshot codec handles
|
|
# integer preservation. Do not accept lossy/unvalidated raw JSON as a save.
|
|
expect(not restored.restore_snapshot(json_copy), "raw floating JSON fields are not silently accepted as integers")
|
|
var valid := split.create_snapshot()
|
|
var fresh := Accrual.new()
|
|
expect(fresh.restore_snapshot(valid), "closed periods restore")
|
|
for change: Dictionary in [
|
|
{"version": 2}, {"current_minute": 1439}, {"started_at": -2},
|
|
{"period_start": 1441}, {"extra": 1}, {"pending_units": {"room": 1}},
|
|
{"closed_periods": []}, {"current_minute": true},
|
|
]:
|
|
var invalid := valid.duplicate(true)
|
|
invalid.merge(change, true)
|
|
expect(not fresh.restore_snapshot(invalid) and fresh.create_snapshot() == valid, "invalid save rejected atomically: %s" % str(change))
|
|
var invalid := valid.duplicate(true)
|
|
invalid.closed_periods.append(invalid.closed_periods[0].duplicate(true))
|
|
expect(not fresh.restore_snapshot(invalid) and fresh.create_snapshot() == valid, "duplicated financial period rejected")
|
|
invalid = valid.duplicate(true)
|
|
invalid.closed_periods[0].facility_units.a = Accrual.MAX_DAILY_RATE * 1440 + 1
|
|
expect(not fresh.restore_snapshot(invalid), "impossible stored amount rejected")
|
|
invalid = valid.duplicate(true)
|
|
invalid.closed_periods[0].period_start = 1
|
|
expect(not fresh.restore_snapshot(invalid), "period gap rejected")
|
|
var empty := Accrual.new()
|
|
expect(fresh.restore_snapshot(empty.create_snapshot()), "unstarted state can restore")
|
|
print("%s: %d checks" % ["PASS" if failures == 0 else "FAIL", checks])
|
|
quit(failures)
|