Skeleton: plugin root, backend socket, /mm router, settings, test harness
The socket connects with the shared-secret header, registers first, reassembles incoming frames of any size (the original dropped anything over 4 KiB) and reconnects two seconds after a failure. Incoming share_* frames go to the vital-sharing handlers; any other frame is a chat-box command for this character, run one per tick through the chat bar as if typed. Frames are written with Newtonsoft.Json defaults, the original's serializer, so the backend sees the same bytes. The secret lives in the character's settings. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
5dbb294a96
31 changed files with 3442 additions and 0 deletions
99
tests/OpenAC.MosswartMassacre.Tests/PluginLifecycleTests.cs
Normal file
99
tests/OpenAC.MosswartMassacre.Tests/PluginLifecycleTests.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using AcDream.Plugin.Abstractions;
|
||||
using OpenAC.MosswartMassacre.Tests.Fakes;
|
||||
|
||||
namespace OpenAC.MosswartMassacre.Tests;
|
||||
|
||||
public sealed class PluginLifecycleTests
|
||||
{
|
||||
[Fact]
|
||||
public void Enable_registers_the_mm_verb_and_login_loads_that_characters_settings()
|
||||
{
|
||||
var host = new FakeHost();
|
||||
host.Automation.IsAvailable = true;
|
||||
host.Automation.Character.Name = "Mossy";
|
||||
var plugin = new MosswartMassacrePlugin();
|
||||
plugin.Initialize(host);
|
||||
plugin.Enable();
|
||||
|
||||
Assert.True(host.Commands.Handlers.ContainsKey("mm"));
|
||||
|
||||
host.Automation.Character.IsInWorld = true;
|
||||
host.Events.RaiseLoginComplete();
|
||||
|
||||
Assert.True(plugin.Context!.IsLoggedIn);
|
||||
Assert.Equal("Mossy", plugin.Context.CharacterName);
|
||||
Assert.Contains("[Mosswart Massacre] Mosswart Massacre has started!", host.ChatLines);
|
||||
Assert.NotNull(host.Storage.ReadText("settings.json"));
|
||||
|
||||
plugin.Disable();
|
||||
Assert.False(host.Commands.Handlers.ContainsKey("mm"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_second_login_is_a_relog_that_switches_character()
|
||||
{
|
||||
using var harness = new PluginHarness("Mossy");
|
||||
harness.Login();
|
||||
harness.Host.Automation.Character.Name = "Horan";
|
||||
|
||||
harness.Plugin.OnLogin();
|
||||
|
||||
Assert.Equal("Horan", harness.Context.CharacterName);
|
||||
Assert.Equal("Horan", harness.Context.Settings.CharacterName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Mm_without_a_subcommand_prints_usage_and_unknown_is_reported()
|
||||
{
|
||||
using var harness = new PluginHarness();
|
||||
harness.Login();
|
||||
|
||||
harness.Context.Commands.Dispatch("");
|
||||
harness.Context.Commands.Dispatch("bogus");
|
||||
|
||||
Assert.Contains("[Mosswart Massacre] Usage: /mm <command>. Try /mm help", harness.ChatLines);
|
||||
Assert.Contains("[Mosswart Massacre] Unknown /mm command: bogus. Try /mm help", harness.ChatLines);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ws_secret_and_url_are_stored_in_settings_not_code()
|
||||
{
|
||||
using var harness = new PluginHarness();
|
||||
harness.Login();
|
||||
|
||||
harness.Context.Commands.Dispatch("ws secret abc 123");
|
||||
harness.Context.Commands.Dispatch("ws url wss://example.test/websocket/");
|
||||
|
||||
Assert.Equal("abc 123", harness.Context.Settings.Current.BackendSecret);
|
||||
Assert.Equal("wss://example.test/websocket/", harness.Context.Settings.Current.BackendUrl);
|
||||
string stored = harness.Host.Storage.ReadText("settings.json")!;
|
||||
Assert.Contains("\"backend_secret\": \"abc 123\"", stored);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Frames_are_not_sent_while_streaming_is_off()
|
||||
{
|
||||
using var harness = new PluginHarness(webSocketEnabled: false);
|
||||
harness.Login();
|
||||
|
||||
harness.Context.Send(new { type = "x" });
|
||||
|
||||
Assert.Empty(harness.Frames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void The_mm_verb_routes_through_the_host_command_registry()
|
||||
{
|
||||
var host = new FakeHost();
|
||||
host.Automation.IsAvailable = true;
|
||||
host.Automation.Character.Name = "Mossy";
|
||||
var plugin = new MosswartMassacrePlugin();
|
||||
plugin.Initialize(host);
|
||||
plugin.Enable();
|
||||
|
||||
host.Commands.Handlers["mm"](new PluginCommand("mm", "help", "/mm help"));
|
||||
|
||||
Assert.Contains("[Mosswart Massacre] Mosswart Massacre Commands:", host.ChatLines);
|
||||
plugin.Disable();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue