acdream/tests/AcDream.App.Tests/UI/Layout/ItemListCellTemplateTests.cs
Erik 22d92315e5 fix(ui): D.2b empty-slot art — container cells use inner slot bg, not the selected-container triangle
Visual gate (2026-06-22) showed the side-bag/main-pack empty cells drawing yellow
triangles. Root cause: the frame-first heuristic grabbed the 36x36 container
prototype's DirectState child 0x06005D9C — which is the open/SELECTED-container
triangle indicator, NOT a background frame — and stamped it onto every empty cell.

Fix: drop frame-first; FindIconEmpty resolves the inner m_elem_Icon ItemSlot_Empty
THROUGH BaseElement inheritance (0x1000033F -> 0x10000340 -> base 0x1000033E ->
0x1000033B -> 0x06000F6E), so containers get the dark slot background matching the
inventory. Pin test now asserts exact ids (0x06004D20 contents / 0x06000F6E
containers) — the old structural-only assertion let the wrong-but-valid 0x06005D9C
pass (Opus review Minor 2, now vindicated). The triangle + green/yellow selection
square is deferred to container-switching (AP-56 reworded). Full suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:45:36 +02:00

75 lines
3.4 KiB
C#

using System;
using System.IO;
using AcDream.App.UI.Layout;
using DatReaderWriter;
using DatReaderWriter.Options;
using Xunit;
using Xunit.Abstractions;
namespace AcDream.App.Tests.UI.Layout;
/// <summary>
/// Real-dat test for <see cref="ItemListCellTemplate.ResolveEmptySprite"/>: the inventory
/// item-lists must resolve their empty-slot sprite from the dat cell template (attribute
/// 0x1000000e -> catalog 0x21000037 prototype's ItemSlot_Empty), NOT the generic toolbar
/// square 0x060074CF. Also PRINTS the resolved ids — the "pin the exact asset" record.
/// Skips when the live dat directory is absent (CI).
/// </summary>
public class ItemListCellTemplateTests
{
private const uint Generic = 0x060074CFu; // generic toolbar-shortcut empty square (the bug)
private const uint ContentsLayout = 0x21000021u; private const uint ContentsGrid = 0x100001C6u;
private const uint BackpackLayout = 0x21000022u; private const uint SideBag = 0x100001CAu;
private const uint MainPack = 0x100001C9u;
private readonly ITestOutputHelper _out;
public ItemListCellTemplateTests(ITestOutputHelper o) => _out = o;
private static string? DatDir()
{
var d = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Documents", "Asheron's Call");
return Directory.Exists(d) ? d : null;
}
[Fact]
public void Inventory_lists_resolve_a_real_nongeneric_empty_sprite()
{
var datDir = DatDir();
if (datDir is null) return; // CI: no live dat — skip (smoke test)
using var dats = new DatCollection(datDir, DatAccessType.Read);
foreach (var (name, layout, elem) in new[]
{
("contents", ContentsLayout, ContentsGrid),
("side-bag", BackpackLayout, SideBag),
("main-pack", BackpackLayout, MainPack),
})
{
uint sprite = ItemListCellTemplate.ResolveEmptySprite(dats, layout, elem);
_out.WriteLine($"{name}: list 0x{elem:X8} (layout 0x{layout:X8}) -> empty sprite 0x{sprite:X8}");
Assert.True(sprite != 0u, $"{name}: resolved 0 (no 0x1000000e attr / prototype / media)");
Assert.True(sprite != Generic, $"{name}: resolved the generic 0x060074CF — the bug, not the fix");
Assert.True((sprite & 0xFF000000u) == 0x06000000u, $"{name}: 0x{sprite:X8} is not a 0x06 RenderSurface id");
}
}
[Fact]
public void Inventory_lists_resolve_the_pinned_retail_sprites()
{
var datDir = DatDir();
if (datDir is null) return; // CI: no live dat — skip
using var dats = new DatCollection(datDir, DatAccessType.Read);
// Pinned from the live dat + the 2026-06-22 visual gate. Contents = the 32x32 prototype's
// ItemSlot_Empty; the 36x36 container/main-pack resolve THROUGH inheritance to their inner
// ItemSlot_Empty (NOT the 0x06005D9C open-container triangle the first cut grabbed — a
// structural-only assertion let that wrong-but-valid 0x06 sprite pass, so we pin exacts).
Assert.Equal(0x06004D20u, ItemListCellTemplate.ResolveEmptySprite(dats, ContentsLayout, ContentsGrid));
Assert.Equal(0x06000F6Eu, ItemListCellTemplate.ResolveEmptySprite(dats, BackpackLayout, SideBag));
Assert.Equal(0x06000F6Eu, ItemListCellTemplate.ResolveEmptySprite(dats, BackpackLayout, MainPack));
}
}