using AcDream.Launcher.Core.Status; namespace AcDream.Launcher.Core.Tests.Status; public sealed class StatusEventParserTests { [Fact] public void ParsesStarted() { var e = StatusEventParser.Parse( """{"v":1,"e":"started","t":"2026-08-14T12:00:00Z","sessionId":"s1"}"""); var started = Assert.IsType(e); Assert.Equal(1, started.V); Assert.Equal("started", started.E); Assert.Equal("s1", started.SessionId); Assert.Equal( DateTimeOffset.Parse("2026-08-14T12:00:00Z"), started.T); } [Fact] public void ParsesConnected() { var e = StatusEventParser.Parse( """{"v":1,"e":"connected","t":"2026-08-14T12:00:01Z","sessionId":"s1"}"""); Assert.IsType(e); } [Fact] public void ParsesCharacterListWithMultipleCharacters() { var e = StatusEventParser.Parse( """ {"v":1,"e":"characterList","t":"2026-08-14T12:00:02Z","sessionId":"s1", "accountName":"testaccount","slotCount":6, "characters":[ {"id":1342177290,"name":"+Acdream","secondsGreyedOut":0}, {"id":1342177291,"name":"+Second","secondsGreyedOut":1} ]} """); var list = Assert.IsType(e); Assert.Equal("testaccount", list.AccountName); Assert.Equal(6, list.SlotCount); Assert.Equal(2, list.Characters.Count); Assert.Equal(1342177290u, list.Characters[0].Id); Assert.Equal("+Acdream", list.Characters[0].Name); Assert.Equal(0, list.Characters[0].SecondsGreyedOut); Assert.Equal(1342177291u, list.Characters[1].Id); Assert.Equal(1, list.Characters[1].SecondsGreyedOut); } [Fact] public void ParsesEnteredWorld() { var e = StatusEventParser.Parse( """{"v":1,"e":"enteredWorld","t":"2026-08-14T12:00:03Z","sessionId":"s1","characterId":1342177290,"characterName":"+Acdream"}"""); var entered = Assert.IsType(e); Assert.Equal(1342177290u, entered.CharacterId); Assert.Equal("+Acdream", entered.CharacterName); } [Fact] public void ParsesPluginLoadedAndPluginFailed() { var loaded = Assert.IsType( StatusEventParser.Parse( """{"v":1,"e":"pluginLoaded","t":"2026-08-14T12:00:04Z","sessionId":"s1","plugin":"ExamplePlugin"}""")); Assert.Equal("ExamplePlugin", loaded.Plugin); var failed = Assert.IsType( StatusEventParser.Parse( """{"v":1,"e":"pluginFailed","t":"2026-08-14T12:00:05Z","sessionId":"s1","plugin":"BadPlugin","error":"boom"}""")); Assert.Equal("BadPlugin", failed.Plugin); Assert.Equal("boom", failed.Error); } [Fact] public void ParsesDisconnectedAndExited() { var disconnected = Assert.IsType( StatusEventParser.Parse( """{"v":1,"e":"disconnected","t":"2026-08-14T12:00:06Z","sessionId":"s1","reason":"serverClosed"}""")); Assert.Equal("serverClosed", disconnected.Reason); var exited = Assert.IsType( StatusEventParser.Parse( """{"v":1,"e":"exited","t":"2026-08-14T12:00:07Z","sessionId":"s1","code":0,"reason":"graceful"}""")); Assert.Equal(0, exited.Code); Assert.Equal("graceful", exited.Reason); } [Fact] public void UnknownEValueSurfacesAsUnknownEventRatherThanThrowing() { var e = StatusEventParser.Parse( """{"v":1,"e":"someFutureEvent","t":"2026-08-14T12:00:08Z","sessionId":"s1","extra":true}"""); var unknown = Assert.IsType(e); Assert.Equal("someFutureEvent", unknown.E); Assert.Equal("s1", unknown.SessionId); Assert.Contains("someFutureEvent", unknown.RawJson); } [Fact] public void MalformedJsonSurfacesAsUnknownEventRatherThanThrowing() { var e = StatusEventParser.Parse("{not json"); Assert.IsType(e); } [Fact] public void KnownEValueWithMissingRequiredFieldSurfacesAsUnknownEventRatherThanThrowing() { // characterList without "characters" — a shape mismatch, not // just an unrecognized e value. var e = StatusEventParser.Parse( """{"v":1,"e":"characterList","t":"2026-08-14T12:00:09Z","sessionId":"s1","accountName":"a","slotCount":6}"""); Assert.IsType(e); } }