using System.Numerics; using AcDream.App.Rendering; using AcDream.App.Rendering.Gpu; using AcDream.App.Tests.Rendering; using AcDream.App.Tests.Rendering.Gpu; using AcDream.App.UI; using AcDream.Content; using AcDream.Core.Items; using AcDream.Plugin.Abstractions; using DatReaderWriter; using DatReaderWriter.Options; using Xunit; namespace AcDream.App.Tests.UI; /// /// Review fix round finding 1 (docs/plans/2026-09-06-plugin-shelf-and-dat-icons.md /// Slice B): must return /// (0, 0, 0) for an id that does not resolve to a real installed /// RenderSurface — NEVER fall through to /// 's 1x1 magenta /// placeholder, which is load-bearing for authored chrome and would /// otherwise get scaled up to a full magenta square by /// // /// (see claude-memory/feedback_ui_resolve_zero_magenta.md: guard on /// the id, never on the resolved handle). /// [Trait("Lane", "InstalledDat")] public sealed class RetailMarkupIconResolverInstalledDatTests { /// /// A Decal-habit "add the block prefix again" mistake applied to an /// already-full DID: 0x06000165 (Melee Defense's real installed /// icon, SampleData.cs:69) plus another 0x06000000 lands at /// 0x0C000165 — a value almost certainly absent from both Portal /// and HighRes. /// private const uint DecalHabitDoubleNormalizedId = 0x0C000165u; /// Retail's Melee Defense skill icon — a known-real installed DID. private const uint KnownRealDid = 0x06000165u; [Fact] public void ResolveDid_UnresolvableId_ReturnsNothing_AndKnownRealId_ReturnsATexture() { string? datDir = InstalledDatTestPath.Resolve(); if (datDir is null) { Assert.Fail( "Lane=InstalledDat requires an installed retail DAT directory; see docs/release-gate.md."); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); using var adapter = new DatCollectionAdapter(dats); var device = new RecordingGpuDevice(); using var cache = new TextureCache(device, adapter); var icons = new IconComposer(adapter, cache); var objects = new ClientObjectTable(); var resolver = new RetailMarkupIconResolver(adapter, cache, icons, objects); (uint missTex, int missW, int missH) = resolver.ResolveDid(DecalHabitDoubleNormalizedId); Assert.Equal((0u, 0, 0), (missTex, missW, missH)); (uint realTex, int realW, int realH) = resolver.ResolveDid(KnownRealDid); Assert.NotEqual(0u, realTex); Assert.True(realW > 0 && realH > 0); } /// /// Residual round finding N1: proves the production wiring fix end to /// end against the REAL resolver — /// now passes iconResolver.ResolveDid (this class) to /// , not /// _bindings.Assets.ResolveSprite (= ResolveChrome = /// , which returns a /// non-zero 1x1 magenta placeholder for a missing id and would have kept /// 's initials fallback /// from ever firing). A bogus descriptor icon id run through the real /// resolver must resolve to nothing, and the shelf button must fall /// back to its initials text — exactly the shape that would have caught /// the pre-fix wiring bug (ResolveSprite would have returned a non-zero /// magenta handle here instead of (0,0,0)). /// [Fact] public void ShelfButton_BogusDescriptorId_OnTheRealResolver_FallsBackToInitials() { string? datDir = InstalledDatTestPath.Resolve(); if (datDir is null) { Assert.Fail( "Lane=InstalledDat requires an installed retail DAT directory; see docs/release-gate.md."); return; } using var dats = new DatCollection(datDir, DatAccessType.Read); using var adapter = new DatCollectionAdapter(dats); var device = new RecordingGpuDevice(); using var cache = new TextureCache(device, adapter); var icons = new IconComposer(adapter, cache); var objects = new ClientObjectTable(); var resolver = new RetailMarkupIconResolver(adapter, cache, icons, objects); var root = new UiRoot { Width = 800f, Height = 600f }; using var shelf = new PluginSidePanel( root.WindowManager, resolver.ResolveDid, font: null); root.AddChild(shelf); var frame = new UiPanel { Width = 200f, Height = 100f }; root.AddChild(frame); RetailWindowHandle handle = root.WindowManager.Register( "plugin:acdream.test:main", frame); shelf.Add( new PluginUiOwner("acdream.test", "Test Plugin"), new PluginPanelDescriptor("main", "Test Plugin") { IconText = "TP", // Already >= the Normalize boundary (0x01000000), so // PluginShelfButton's ctor leaves it unchanged — a real DID // shape that is nonetheless absent from both Portal and // HighRes (see DecalHabitDoubleNormalizedId's own doc above). IconSurfaceId = DecalHabitDoubleNormalizedId, }, handle); PluginSidePanel.PluginShelfButton button = Assert.Single( shelf.Children.OfType()); Assert.Equal(string.Empty, button.Text); var textRenderer = new TextRenderer(device, new NullGpuFrameSource(), "unused"); textRenderer.Begin(new Vector2(200f, 200f)); var ctx = new UiRenderContext(textRenderer, new Vector2(200f, 200f)); button.DrawSelfAndChildren(ctx); Assert.Equal("TP", button.Text); } private sealed class NullGpuFrameSource : ICurrentGpuFrameSource { public IGpuFrame? CurrentFrame => null; } }