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)