Files
riojoy/tests/RioJoy.Core.Tests/Overlay/OverlayHitTesterTests.cs
T
CydandClaude Fable 5 0623891f74 Phase 7: wallpaper maker (live preview, click-to-edit labels, .data import)
The interactive replacement for the legacy Sheet -> GIMP/Script-Fu pipeline:
WallpaperMakerForm (tray -> "Wallpaper maker") renders the profile wallpaper
live via SkiaOverlayRenderer, outlines all 119 template cells, and lets any
cell -- including the heading/banner cells the button editor cannot reach --
be clicked and retitled with debounced re-render. Clicks on stacked cells
cycle through the regions at that pixel (OverlayHitTester, unit-tested);
stacking is legitimate chroma-split display encoding. Imports a legacy .data
sheet row (with a game picker for multi-row sheets), exports the PNG, and can
apply the desktop wallpaper immediately to the same per-profile path the
runtime uses. Prompts for and remembers AppConfig.OverlayTemplatePath on
first use. PLAN.md: record this + the completed Phase 6 deploy package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 00:54:54 -05:00

74 lines
2.2 KiB
C#

using RioJoy.Core.Overlay;
using Xunit;
namespace RioJoy.Core.Tests.Overlay;
public class OverlayHitTesterTests
{
// Two stacked cells (the chroma-split overlap case) + one disjoint cell.
private static OverlayTemplate Template() => new()
{
Width = 1000,
Height = 400,
Regions =
{
new OverlayRegion { Name = "big", X = 0, Y = 0, Width = 200, Height = 100 },
new OverlayRegion { Name = "small", X = 50, Y = 25, Width = 100, Height = 50 },
new OverlayRegion { Name = "solo", X = 500, Y = 200, Width = 80, Height = 40 },
},
};
[Fact]
public void RegionsAt_ReturnsSmallestFirst()
{
IReadOnlyList<OverlayRegion> hits = OverlayHitTester.RegionsAt(Template(), 100, 50);
Assert.Equal(new[] { "small", "big" }, hits.Select(r => r.Name));
}
[Fact]
public void RegionsAt_MissReturnsEmpty()
{
Assert.Empty(OverlayHitTester.RegionsAt(Template(), 999, 399));
}
[Fact]
public void RegionsAt_EdgesAreInclusiveLeftTop_ExclusiveRightBottom()
{
OverlayTemplate t = Template();
Assert.Contains(OverlayHitTester.RegionsAt(t, 500, 200), r => r.Name == "solo");
Assert.Empty(OverlayHitTester.RegionsAt(t, 580, 240)); // right/bottom edge excluded
}
[Fact]
public void NextAt_FirstClickSelectsSmallest()
{
OverlayRegion? hit = OverlayHitTester.NextAt(Template(), 100, 50, currentName: null);
Assert.Equal("small", hit?.Name);
}
[Fact]
public void NextAt_CyclesThroughStackAndWraps()
{
OverlayTemplate t = Template();
Assert.Equal("big", OverlayHitTester.NextAt(t, 100, 50, "small")?.Name);
Assert.Equal("small", OverlayHitTester.NextAt(t, 100, 50, "big")?.Name); // wrap
Assert.Equal("small", OverlayHitTester.NextAt(t, 100, 50, "SOLO")?.Name); // current not in stack
}
[Fact]
public void NextAt_CurrentNameIsCaseInsensitive()
{
Assert.Equal("big", OverlayHitTester.NextAt(Template(), 100, 50, "SMALL")?.Name);
}
[Fact]
public void NextAt_MissReturnsNull()
{
Assert.Null(OverlayHitTester.NextAt(Template(), 5, 395, "small"));
}
}