class ERR_ProfileProbe { static void Require(bool success, string detail) { if (success) Print("ERR CONFIG PASS " + detail); else Print("ERR CONFIG FAIL " + detail, LogLevel.ERROR); } static void Run() { map extra; Require(ERR_ProfileConfig.Document(ERR_ProfileConfig.PATH, extra), "initial migration exists"); extra.Set("future", "{\"nested\":[\"comma , brace } escaped \\\" quote\",{\"value\":12}]}"); Require(ERR_ProfileConfig.Commit(extra), "unknown root extension"); ERR_Settings settings = new ERR_Settings(); Require(settings.Get("heliTimerMinutes") == 27, "legacy mission import"); ERR_TerrainPreference terrain = new ERR_TerrainPreference(); Require(terrain.Scenario() == "", "terrain import"); ERR_ItemPreferences items = new ERR_ItemPreferences(); Require(!items.Enabled("1111111111111111", "aaaaaaaaaaaaaaaa"), "item import"); Require(settings.Set("heliTimerMinutes", 42), "mission save"); Require(items.Preset("save", "custom"), "preset save"); Require(terrain.Save("{C1E20667DCE324ED}Missions/ERR_Everon.conf"), "terrain save"); ERR_ContentSettings content = new ERR_ContentSettings(); ERR_FactionSelection factions = new ERR_FactionSelection(); Require(factions.Save({"random", "ussr", "fia"}, content), "factions save"); foreach (ERR_ContentOption option : ERR_ContentRegistry.Definition().Options) { Require(content.Set(option.Id, 0), "mods save"); break; } ERR_Settings reload = new ERR_Settings(); Require(reload.Get("heliTimerMinutes") == 42, "other sections do not clobber mission"); JsonLoadContext voice = new JsonLoadContext(); string url; Require(ERR_ProfileConfig.Load(ERR_ProfileConfig.VOICE, voice) && voice.ReadValue("welcomeUrl", url) && url == "http://192.168.52.4:18947/welcome.b64", "voice preserved"); map document; Require(ERR_ProfileConfig.Document(ERR_ProfileConfig.PATH, document), "document readback"); Require(document.Contains("future") && document.Get("future") == extra.Get("future"), "unknown root preserved"); map split = new map(); Require(!ERR_ProfileConfig.Split("{\"x\":1,\"x\":2}", split), "duplicate root rejected"); Require(!ERR_ProfileConfig.Split("[1,2]", split), "nonobject root rejected"); string longText; for (int i = 0; i < 4096; i++) longText += "a"; JsonSaveContext longJson = new JsonSaveContext(); longJson.WriteValue("long", longText); longJson.WriteValue("quoted", "\"{},[]\\"); Require(ERR_ProfileConfig.Split(longJson.SaveToString(), split) && split.Count() == 2, "block boundary and escaping"); // A corrupt primary recovers the last valid complete document on the next write. FileHandle bad = FileIO.OpenFile(ERR_ProfileConfig.PATH, FileMode.WRITE); bad.Write("bad json"); bad.Close(); ERR_Settings recovered = new ERR_Settings(); Require(recovered.Get("heliTimerMinutes") == 42 && recovered.Set("heliTimerMinutes", 43), "backup recovery"); Require(FileIO.FileExists(ERR_Settings.PATH) && FileIO.FileExists(ERR_ItemPreferences.PATH), "legacy originals retained"); // Changing a legacy file after migration must never reactivate old settings. FileHandle stale = FileIO.OpenFile(ERR_Settings.PATH, FileMode.WRITE); stale.Write("{}"); stale.Close(); ERR_Settings retained = new ERR_Settings(); Require(retained.Get("heliTimerMinutes") == 43, "legacy ignored after migration"); FileIO.CopyFile(ERR_ProfileConfig.PATH, "$profile:verified-config.json"); FileHandle future = FileIO.OpenFile(ERR_ProfileConfig.PATH, FileMode.WRITE); future.Write("{\"configVersion\":2}"); future.Close(); ERR_Settings unsupported = new ERR_Settings(); Require(!unsupported.Set("heliTimerMinutes", 10), "future version cannot downgrade through backup"); string untouched; ERR_ProfileConfig.Text(ERR_ProfileConfig.PATH, untouched); Require(untouched == "{\"configVersion\":2}", "future file preserved"); FileIO.DeleteFile(ERR_ProfileConfig.PATH); FileIO.DeleteFile(ERR_ProfileConfig.PATH + ".bak"); foreach (string legacy : ERR_ProfileConfig.LegacyPaths()) { FileIO.DeleteFile(legacy); FileIO.DeleteFile(legacy + ".bak"); } FileHandle invalid = FileIO.OpenFile(ERR_ProfileConfig.VOICE, FileMode.WRITE); invalid.Write("{\"welcomeUrl\":123}"); invalid.Close(); Require(!ERR_ProfileConfig.Ensure() && !FileIO.FileExists(ERR_ProfileConfig.PATH), "invalid migration blocks instead of losing settings"); JsonSaveContext backup = new JsonSaveContext(); backup.WriteValue("welcomeUrl", "http://192.168.52.4:18947/welcome.b64"); backup.SaveToFile(ERR_ProfileConfig.VOICE + ".bak"); Require(ERR_ProfileConfig.Ensure(), "valid legacy backup imported"); ERR_Settings fresh = new ERR_Settings(); Require(fresh.Get("heliTimerMinutes") == 15 && fresh.Get("responseRadiusMetres") == 2000, "missing files receive mission defaults"); JsonLoadContext recoveredVoice = new JsonLoadContext(); Require(ERR_ProfileConfig.Load(ERR_ProfileConfig.VOICE, recoveredVoice) && recoveredVoice.ReadValue("welcomeUrl", url) && url == "http://192.168.52.4:18947/welcome.b64", "voice backup retained"); Print("ERR CONFIG COMPLETE"); } } modded class ArmaReforgerScripted { protected bool m_ERRConfigProbe; override void OnUpdate(BaseWorld world, float timeslice) { super.OnUpdate(world, timeslice); if (m_ERRConfigProbe) return; m_ERRConfigProbe = true; ERR_ProfileProbe.Run(); } }