using AcDream.App.UI; using AcDream.App.UI.Layout; using AcDream.Core.Combat; using AcDream.Core.Items; using AcDream.Core.Net.Messages; using AcDream.Core.Spells; namespace AcDream.App.Tests.UI.Layout; public sealed class AppraisalUiControllerTests { private const uint ObjectId = 0x50000001u; [Fact] public void ItemResponse_UsesAuthoredItemSubviewTitleAndScrollbars() { ImportedLayout layout = FixtureLoader.LoadExamination(); var objects = new ClientObjectTable(); objects.AddOrUpdate(new ClientObject { ObjectId = ObjectId, Name = "Atlan Weapon", Type = ItemType.MeleeWeapon, Value = 1250, Burden = 350, }); var sent = new List(); using var interaction = NewInteraction(objects, sent); var combat = new CombatState(); int shown = 0; int closed = 0; using AppraisalUiController controller = AppraisalUiController.Bind( layout, objects, interaction, combat, new Spellbook(), () => shown++, () => closed++)!; Assert.True(interaction.ExamineSelectedOrEnterMode(ObjectId)); var properties = new PropertyBundle(); properties.Strings[16u] = "A finely balanced weapon."; properties.Strings[7u] = "Remember the fallen."; properties.Strings[8u] = "Tester"; Assert.True(controller.Apply(Parsed(properties))); Assert.Equal(1, shown); Assert.Equal(AppraisalView.Item, controller.ActiveView); Assert.Equal(0, interaction.BusyCount); UiText title = Assert.IsType( layout.FindElement(AppraisalUiController.TitleId)); Assert.Equal("Atlan Weapon", Assert.Single(title.LinesProvider()).Text); UiText itemText = Assert.IsType( layout.FindElement(AppraisalUiController.ItemTextId)); string report = string.Join('\n', itemText.LinesProvider().Select(line => line.Text)); Assert.Contains("Value: 1,250", report); Assert.Contains("Burden: 350", report); Assert.Contains("A finely balanced weapon.", report); UiScrollbar scrollbar = Assert.IsType( layout.FindElement(AppraisalUiController.ItemScrollbarId)); Assert.Same(itemText.Scroll, scrollbar.Model); UiField inscription = Assert.IsType( layout.FindElement(AppraisalUiController.InscriptionTextId)); Assert.Contains("Remember the fallen", inscription.Text); Assert.False(inscription.Enabled); UiText signature = Assert.IsType( layout.FindElement(AppraisalUiController.SignatureTextId)); Assert.Equal("Inscribed by Tester", Assert.Single(signature.LinesProvider()).Text); ((UiButton)layout.FindElement(AppraisalUiController.CloseId)!).OnClick!.Invoke(); Assert.Equal(1, closed); } [Fact] public void CreatureResponse_SelectsCreatureSubviewAndRefreshesInCombatWithoutBusy() { ImportedLayout layout = FixtureLoader.LoadExamination(); var objects = new ClientObjectTable(); objects.AddOrUpdate(new ClientObject { ObjectId = ObjectId, Name = "Drudge Slinker", Type = ItemType.Creature, }); var sent = new List(); using var interaction = NewInteraction(objects, sent); var combat = new CombatState(); int shown = 0; using AppraisalUiController controller = AppraisalUiController.Bind( layout, objects, interaction, combat, new Spellbook(), () => shown++, () => { })!; interaction.ExamineSelectedOrEnterMode(ObjectId); var properties = new PropertyBundle(); properties.Ints[25u] = 12; var creature = new AppraiseInfoParser.CreatureProfile( Flags: 0, Health: 80, HealthMax: 100, Strength: null, Endurance: null, Quickness: null, Coordination: null, Focus: null, Self: null, Stamina: null, Mana: null, StaminaMax: null, ManaMax: null, AttributeHighlights: null, AttributeColors: null); Assert.True(controller.Apply(Parsed(properties, creature))); Assert.Equal(AppraisalView.Creature, controller.ActiveView); Assert.Equal(1, shown); Assert.False(layout.FindElement(AppraisalUiController.ItemPanelId)!.Visible); Assert.True(layout.FindElement(AppraisalUiController.CreaturePanelId)!.Visible); combat.SetCombatMode(CombatMode.Melee); controller.Tick(0.74); Assert.Single(sent); controller.Tick(0.01); Assert.Equal(new[] { ObjectId, ObjectId }, sent); Assert.Equal(0, interaction.BusyCount); layout.Root.Visible = false; controller.Tick(0.75); Assert.Equal(new[] { ObjectId, ObjectId }, sent); Assert.True(controller.Apply(Parsed(properties, creature))); Assert.Equal(1, shown); } [Fact] public void ResponseForNeitherPendingNorCurrent_IsIgnored() { ImportedLayout layout = FixtureLoader.LoadExamination(); var objects = new ClientObjectTable(); objects.AddOrUpdate(new ClientObject { ObjectId = ObjectId, Name = "Item" }); using var interaction = NewInteraction(objects, []); using AppraisalUiController controller = AppraisalUiController.Bind( layout, objects, interaction, new CombatState(), new Spellbook(), () => throw new InvalidOperationException("must not show"), () => { })!; Assert.False(controller.Apply(Parsed(new PropertyBundle()))); Assert.Equal(0u, controller.CurrentObjectId); } private static ItemInteractionController NewInteraction( ClientObjectTable objects, List sent) => new( objects, playerGuid: () => 0x50000002u, sendUse: null, sendUseWithTarget: null, sendWield: null, sendDrop: null, sendExamine: sent.Add); private static AppraiseInfoParser.Parsed Parsed( PropertyBundle properties, AppraiseInfoParser.CreatureProfile? creature = null) => new( Guid: ObjectId, Flags: creature is null ? AppraiseInfoParser.IdentifyResponseFlags.IntStatsTable : AppraiseInfoParser.IdentifyResponseFlags.CreatureProfile, Success: true, Properties: properties, SpellBook: [], ArmorProfile: null, CreatureProfile: creature, WeaponProfile: null, HookProfile: null, ArmorLevels: null, ArmorEnchantments: null, WeaponEnchantments: null, ResistEnchantments: null); }