using Newtonsoft.Json.Linq; namespace OpenAC.MosswartMassacre.Tests.Backend; public sealed class BackendSessionTests { [Fact] public void A_command_for_this_character_runs_as_typed_on_the_next_tick() { using var harness = new PluginHarness("Mossy"); harness.Login(); harness.Receive("{\"player_name\":\"mossy\",\"command\":\"/a hello\"}"); Assert.Empty(harness.Host.Automation.Chat.Submitted); harness.Tick(0.01); Assert.Equal(["/a hello"], harness.Host.Automation.Chat.Submitted); } [Fact] public void A_command_for_another_character_is_ignored() { using var harness = new PluginHarness("Mossy"); harness.Login(); harness.Receive("{\"player_name\":\"Horan\",\"command\":\"/a hello\"}"); harness.Tick(0.01); Assert.Empty(harness.Host.Automation.Chat.Submitted); } [Fact] public void Commands_run_one_per_tick_in_arrival_order() { using var harness = new PluginHarness("Mossy"); harness.Login(); harness.Receive("{\"player_name\":\"Mossy\",\"command\":\"/one\"}"); harness.Receive("{\"player_name\":\"Mossy\",\"command\":\"/two\"}"); harness.Tick(0.01); Assert.Equal(["/one"], harness.Host.Automation.Chat.Submitted); harness.Tick(0.01); Assert.Equal(["/one", "/two"], harness.Host.Automation.Chat.Submitted); } [Fact] public void Radar_commands_toggle_the_radar_instead_of_chat() { using var harness = new PluginHarness("Mossy"); harness.Login(); var toggles = new List(); harness.Session.RadarToggle = on => toggles.Add(on); harness.Receive("{\"player_name\":\"Mossy\",\"command\":\"start_radar\"}"); harness.Receive("{\"player_name\":\"Mossy\",\"command\":\"stop_radar\"}"); harness.Tick(0.01); harness.Tick(0.01); Assert.Equal([true, false], toggles); Assert.Empty(harness.Host.Automation.Chat.Submitted); } [Fact] public void Share_frames_go_to_the_share_handlers_whoever_they_name() { using var harness = new PluginHarness("Mossy"); var seen = new List(); harness.Session.AddShareHandler(new RecordingShareHandler(seen)); harness.Login(); harness.Receive("{\"type\":\"share_vital_update\",\"character_name\":\"Horan\"}"); Assert.Equal(["share_vital_update"], seen); harness.Tick(0.01); Assert.Empty(harness.Host.Automation.Chat.Submitted); } [Fact] public void Malformed_frames_are_skipped() { using var harness = new PluginHarness("Mossy"); harness.Login(); harness.Receive("not json"); harness.Receive("[1,2,3]"); harness.Tick(0.01); Assert.Empty(harness.Host.Automation.Chat.Submitted); } [Fact] public void Connecting_sets_the_per_connection_session_id() { using var harness = new PluginHarness("Mossy"); harness.Login(); harness.Session.OnConnected(new DateTime(2026, 9, 25, 8, 5, 9, DateTimeKind.Utc)); Assert.Equal("Mossy-20260925-080509", harness.Context.ConnectionSessionId); } private sealed class RecordingShareHandler(List seen) : IShareFrameHandler { public void HandleShareFrame(string type, JObject frame) => seen.Add(type); } }