using AcDream.Plugin.Abstractions; using OpenAC.MosswartMassacre.FlagTracker; using OpenAC.MosswartMassacre.Tests.Fakes; namespace OpenAC.MosswartMassacre.Tests.FlagTracker; public sealed class FlagTrackerTests { private const uint Player = 0x50000001; private static PluginHarness WithUi(Action? arrange = null) => new(arrange: host => { host.HasUi = true; arrange?.Invoke(host); }); private static void SetPlayerInts(FakeHost host, Dictionary ints) => host.Automation.Objects.Properties[Player] = new PluginItemProperties( ints, new Dictionary(), new Dictionary(), new Dictionary(), new Dictionary(), new Dictionary(), new Dictionary()); private static FlagTrackerViewModel Panel(PluginHarness harness) => harness.Feature().Panel!; private static int Row(IReadOnlyList names, string name) { int index = names.ToList().IndexOf(name); Assert.True(index >= 0, $"no row {name}"); return index; } [Fact] public void A_headless_host_gets_no_window_and_login_does_nothing() { using var harness = new PluginHarness(); harness.Login(); harness.Run(6); FlagTrackerFeature feature = harness.Feature(); Assert.Null(feature.Panel); Assert.Empty(harness.Host.Ui.Panels); } [Fact] public void A_graphical_host_gets_the_mossy_tracker_window_closed() { using var harness = WithUi(); RegisteredPanel panel = Assert.Single(harness.Host.Ui.Panels); Assert.Equal("flagtracker", panel.Descriptor.WindowId); Assert.Equal("Mossy Tracker", panel.Descriptor.Title); Assert.True(panel.Descriptor.ShowInSidePanel); Assert.EndsWith(FlagTrackerFeature.MarkupFile, panel.MarkupPath, StringComparison.Ordinal); Assert.Same(Panel(harness), panel.Binding); Assert.False(Panel(harness).IsVisible); Assert.True(Panel(harness).AugsSelected); Panel(harness).ShowQuests(); Assert.True(Panel(harness).QuestsSelected); Assert.False(Panel(harness).AugsSelected); } [Fact] public void Augmentations_come_from_the_players_own_properties() { using var harness = WithUi(host => SetPlayerInts(host, new() { [231] = 3, [230] = 2 })); harness.Login(); FlagTrackerViewModel panel = Panel(harness); Assert.Equal("--- Death Augs ---", panel.AugNames[0]); int keepItems = Row(panel.AugNames, "Keep Items"); Assert.Equal("[MAX]", panel.AugProgress[keepItems]); Assert.Equal(0x008000u, panel.AugProgressColors[keepItems]); Assert.Equal("Rohula bint Ludun", panel.AugTrainers[keepItems]); Assert.Equal("Ayan Baqur", panel.AugLocations[keepItems]); int keepSpells = Row(panel.AugNames, "Keep Spells"); Assert.Equal("[0/1]", panel.AugProgress[keepSpells]); Assert.Equal(0xFF0000u, panel.AugProgressColors[keepSpells]); int carrying = Row(panel.AugNames, "Extra Carrying Capacity"); Assert.Equal("[2/5]", panel.AugProgress[carrying]); Assert.Equal(0xFFFF00u, panel.AugProgressColors[carrying]); // A bought augmentation shows after Refresh. SetPlayerInts(harness.Host, new() { [232] = 1 }); panel.RefreshAugs(); Assert.Equal("[MAX]", panel.AugProgress[keepSpells]); } [Fact] public void Luminance_auras_show_progress_and_the_seer_they_belong_to() { using var harness = WithUi(host => SetPlayerInts(host, new() { [333] = 5, [344] = 2 })); harness.Login(); FlagTrackerViewModel panel = Panel(harness); int damage = Row(panel.LumNames, "+1 Damage Rating"); Assert.Equal("5/5", panel.LumProgress[damage]); Assert.Equal(0x008000u, panel.LumProgressColors[damage]); Assert.Equal("Nalicana Auras", panel.LumCategories[damage]); int kahiri = Row(panel.LumNames, "(Ka'hiri) +2 Specialized Skills"); Assert.Equal("2/5", panel.LumProgress[kahiri]); Assert.Equal(0xFFFF00u, panel.LumProgressColors[kahiri]); Assert.Equal("LoyalToKahiri", panel.LumCategories[kahiri]); } [Fact] public void Recalls_show_known_and_unknown_with_their_spell_icons() { using var harness = WithUi(host => host.Automation.Spells.KnownSpellIds.Add(2023)); harness.Login(); FlagTrackerViewModel panel = Panel(harness); Assert.Equal(17, panel.RecallNames.Count); Assert.Equal("Recall the Sanctuary", panel.RecallNames[0]); Assert.Equal(2023u, panel.RecallSpellIds[0]); Assert.Equal("Known", panel.RecallStatus[0]); Assert.Equal(0x008000u, panel.RecallStatusColors[0]); Assert.Equal("Unknown", panel.RecallStatus[1]); Assert.Equal(0xFF0000u, panel.RecallStatusColors[1]); } [Fact] public void Cantrips_are_matched_to_trained_skills_attributes_and_wards() { using var harness = WithUi(host => { host.Automation.Character.Skills.Add(new PluginSkillInfo(34, "War Magic", PluginSkillTraining.Specialized, 400)); host.Automation.Character.Skills.Add(new PluginSkillInfo(6, "Melee Defense", PluginSkillTraining.Trained, 300)); host.Automation.Character.Skills.Add(new PluginSkillInfo(21, "Healing", PluginSkillTraining.Untrained, 10)); host.Automation.Spells.All = [ FakeSpellCatalog.Spell(4715, "Epic War Magic Aptitude"), FakeSpellCatalog.Spell(2248, "Major Invulnerability"), FakeSpellCatalog.Spell(1, "Minor Invulnerability"), FakeSpellCatalog.Spell(6099, "Legendary Flame Ward"), FakeSpellCatalog.Spell(2091, "Major Strength"), FakeSpellCatalog.Spell(2, "Strength Self VIII"), ]; host.Automation.Character.ActiveEnchantments = [ new PluginActiveEnchantment(4715, 0, 0, -1), new PluginActiveEnchantment(2248, 0, 0, -1), new PluginActiveEnchantment(1, 0, 0, -1), new PluginActiveEnchantment(6099, 0, 0, -1), new PluginActiveEnchantment(2091, 0, 0, -1), new PluginActiveEnchantment(2, 0, 0, 3600), ]; }); harness.Login(); FlagTrackerViewModel panel = Panel(harness); Assert.Equal( [ "--- Specialized Skills ---", "War Magic", "--- Trained Skills ---", "Invulnerability", "--- Attributes ---", "Strength", "--- Protection Auras ---", "Armor", "Bludgeoning Ward", "Piercing Ward", "Slashing Ward", "Flame Ward", "Frost Ward", "Acid Ward", "Storm Ward", ], panel.CantripNames); Assert.Equal(FlagTrackerData.Icons.CategoryStar, panel.CantripIcons[0]); Assert.Equal("Epic", panel.CantripLevels[1]); Assert.Equal(0x800080u, panel.CantripLevelColors[1]); Assert.Equal(FlagTrackerData.Icons.GreenCircle, panel.CantripIcons[1]); // The higher of two cantrips on one skill wins. Assert.Equal("Major", panel.CantripLevels[3]); Assert.Equal(0x0000FFu, panel.CantripLevelColors[3]); Assert.Equal("Major", panel.CantripLevels[5]); Assert.Equal("N/A", panel.CantripLevels[7]); Assert.Equal(FlagTrackerData.Icons.RedCircle, panel.CantripIcons[7]); int flame = Row(panel.CantripNames, "Flame Ward"); Assert.Equal("Legendary", panel.CantripLevels[flame]); Assert.Equal(0xFFA500u, panel.CantripLevelColors[flame]); } [Fact] public void Tracked_weapons_are_found_in_the_inventory_by_name() { using var harness = WithUi(host => host.Automation.Items.Owned.Add( FakeItems.Item(0x80000001, "Atlan Sword") with { IconId = 0x06001234 })); harness.Login(); FlagTrackerViewModel panel = Panel(harness); int atlan = Row(panel.WeaponNames, "Atlan Sword"); Assert.Equal("Acquired", panel.WeaponStatus[atlan]); Assert.Equal(0x06001234u, panel.WeaponIcons[atlan]); int axe = Row(panel.WeaponNames, "Atlan Axe"); Assert.Equal("Not Acquired", panel.WeaponStatus[axe]); Assert.Equal(FlagTrackerData.Icons.Portal, panel.WeaponIcons[axe]); } [Fact] public void The_quest_page_hides_maxed_quests_and_sorts_by_solves() { using var harness = WithUi(); harness.Login(); long now = new DateTimeOffset(harness.Clock.UtcNow).ToUnixTimeSeconds(); var chat = harness.Host.Automation.Chat; chat.Deliver($"stipendtimer_0812 - 2 solves ({now - 10})\"x\" -1 3700"); chat.Deliver($"maxed - 5 solves ({now})\"x\" 5 60"); chat.Deliver($"aaa - 7 solves ({now - 100})\"x\" -1 50"); FlagTrackerViewModel panel = Panel(harness); Assert.Equal(["aaa", "Stipend Collection Timer"], panel.QuestRowNames); Assert.Equal(["READY", "1h 01m"], panel.QuestCountdowns); Assert.Equal([0x008000u, 0xFFFF00u], panel.QuestCountdownColors); Assert.Equal(["50s", "1h 1m 40s"], panel.QuestCooldowns); Assert.Equal(["7", "2"], panel.QuestSolves); // The countdowns move on every five seconds. harness.Run(5.1); Assert.Equal("1h 01m", panel.QuestCountdowns[1]); harness.Run(120); Assert.StartsWith("59m ", panel.QuestCountdowns[1], StringComparison.Ordinal); } [Fact] public void Logoff_empties_the_pages() { using var harness = WithUi(); harness.Login(); Assert.NotEmpty(Panel(harness).AugNames); harness.Plugin.OnLogoff(); Assert.Empty(Panel(harness).AugNames); Assert.Empty(Panel(harness).QuestRowNames); } }