using AcDream.Plugin.Abstractions;
using OpenAC.MosswartMassacre.Backend;
using OpenAC.MosswartMassacre.Streams;
namespace OpenAC.MosswartMassacre.Tests.Streams;
/// The character_stats frame as the original's CharacterStats.CollectAndSend wrote it.
public sealed class CharacterStatsTests
{
private const string Stamp = "2026-09-25T08:30:15.1230000Z";
private static PluginHarness Arranged()
{
var harness = new PluginHarness("Mossy");
var c = harness.Host.Automation.Character;
c.Level = 126;
c.Attributes =
[
new PluginAttributeInfo(0, "Strength", 300u) { Base = 290u, Ranks = 190u },
new PluginAttributeInfo(1, "Endurance", 200u) { Base = 200u, Ranks = 100u },
];
c.Vitals = [new PluginVitalInfo(0, "Health", 300u, 341u) { Base = 331u }];
c.Skills.Add(new PluginSkillInfo(34u, "War Magic", PluginSkillTraining.Specialized, 540u) { Base = 533u });
c.Skills.Add(new PluginSkillInfo(6u, "Melee Defense", PluginSkillTraining.Trained, 400u) { Base = 388u });
harness.Host.Automation.Objects.Properties[0x50000001] = new PluginItemProperties(
new Dictionary
{
[5] = 9000, // burden units (blacklisted from properties)
[24] = 3, // skill credits (blacklisted)
[43] = 12, // deaths (blacklisted)
[98] = 1_000_000_000, // creation time (blacklisted)
[230] = 2, // carrying-capacity augmentations
[218] = 1, // an augmentation: kept
},
new Dictionary { [1] = 123_456_789_012L, [2] = 5_000L, [6] = 500_000L },
new Dictionary(),
new Dictionary(),
new Dictionary { [3] = "Male", [4] = "Aluvian" },
new Dictionary(),
new Dictionary());
harness.Login();
harness.Frames.Clear();
return harness;
}
[Fact]
public void The_frame_keeps_the_originals_fields_order_and_types()
{
// CharacterStats.cs:252-383. burden = (int)((float)9000 / (300*150) * 100) = 20;
// capacity = 150*300 + 2*30*300 = 63000; birth = 1970 + 1e9 s in en-US.
using var harness = Arranged();
var stream = harness.Feature();
stream.CurrentTitle = () => 42;
stream.Titles = () => ["Adventurer", "Sawato Resident"];
stream.Allegiance = () => new AllegianceSummary(
"Mossy Club", new AllegianceMember("King", 1, 8, 1), null, 3, 17);
string json = Wire.Serialize(stream.Build());
Assert.Equal(
"{\"type\":\"character_stats\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"level\":126,\"race\":\"Aluvian\",\"gender\":\"Male\",\"birth\":\"9/9/2001 1:46:40 AM\","
+ "\"total_xp\":123456789012,\"unassigned_xp\":5000,\"skill_credits\":3,\"deaths\":12,"
+ "\"burden\":20,\"burden_units\":9000,\"encumbrance_capacity\":63000,"
+ "\"luminance_earned\":500000,\"luminance_total\":null,\"current_title\":42,"
+ "\"attributes\":{\"strength\":{\"base\":290,\"creation\":100},\"endurance\":{\"base\":200,\"creation\":100}},"
+ "\"vitals\":{\"health\":{\"base\":331}},"
+ "\"skills\":{\"melee_defense\":{\"base\":388,\"training\":\"Trained\"},\"war_magic\":{\"base\":533,\"training\":\"Specialized\"}},"
+ "\"allegiance\":{\"name\":\"Mossy Club\",\"monarch\":{\"name\":\"King\",\"race\":1,\"rank\":8,\"gender\":1},\"patron\":null,\"rank\":3,\"followers\":17},"
+ "\"properties\":{\"230\":2,\"218\":1},"
+ "\"titles\":[\"Adventurer\",\"Sawato Resident\"]}",
json);
}
[Fact]
public void Unknown_title_and_allegiance_are_null()
{
using var harness = Arranged();
string json = Wire.Serialize(harness.Feature().Build());
Assert.Contains("\"current_title\":null,", json, StringComparison.Ordinal);
Assert.Contains("\"allegiance\":null,", json, StringComparison.Ordinal);
Assert.EndsWith("\"titles\":null}", json, StringComparison.Ordinal);
}
[Fact]
public void Sent_five_seconds_after_login_then_every_ten_minutes()
{
using var harness = Arranged();
harness.Run(4.5, 0.5);
Assert.Empty(harness.FramesOfType("character_stats"));
harness.Run(0.6, 0.1);
Assert.Single(harness.FramesOfType("character_stats"));
harness.Run(600, 5);
Assert.Equal(2, harness.FramesOfType("character_stats").Count());
}
}