test(selftest): pin the sidebar active-surface invariant
Drives the real Sidebar.Draw and reads the render counter, so a regression in the draw path fails instead of a parallel calculation passing. Three cases: one of two tabs active draws exactly one surface, a null active tab draws zero, and icon-only mode still marks the active row. Zero is a legitimate state, not a failure -- PickMainActiveTab returns null when every tab is popped out, so the invariant is "at most one", not "exactly one".
This commit is contained in:
@@ -454,6 +454,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
|||||||
new SelfTests.TellResetOnActivateStep(),
|
new SelfTests.TellResetOnActivateStep(),
|
||||||
new SelfTests.CurrentTabCouplingStep(this),
|
new SelfTests.CurrentTabCouplingStep(this),
|
||||||
new SelfTests.SidebarUnreadDotStep(this),
|
new SelfTests.SidebarUnreadDotStep(this),
|
||||||
|
new SelfTests.SidebarActiveSurfaceStep(this),
|
||||||
new SelfTests.UnreadDecisionStep(),
|
new SelfTests.UnreadDecisionStep(),
|
||||||
new SelfTests.CurrentTabGuidedStep(this),
|
new SelfTests.CurrentTabGuidedStep(this),
|
||||||
new SelfTests.CardClipPlanStep(this),
|
new SelfTests.CardClipPlanStep(this),
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Plugin.SelfTest;
|
||||||
|
using HellionChat.Code;
|
||||||
|
|
||||||
|
namespace HellionChat.SelfTests;
|
||||||
|
|
||||||
|
// v1.10.0/C3: the active row gets a surface and an accent bar, so exactly the
|
||||||
|
// row the user is on must be marked -- and only that one. Drives the real
|
||||||
|
// Sidebar.Draw and reads the render-observability counter, so a regression in
|
||||||
|
// the draw path fails rather than a parallel calculation passing.
|
||||||
|
//
|
||||||
|
// "At most one", not "exactly one": PickMainActiveTab returns null when every
|
||||||
|
// tab is popped out, which is a legitimate state with zero marked rows.
|
||||||
|
internal sealed class SidebarActiveSurfaceStep : ISelfTestStep
|
||||||
|
{
|
||||||
|
private readonly Plugin _plugin;
|
||||||
|
|
||||||
|
public SidebarActiveSurfaceStep(Plugin plugin) => _plugin = plugin;
|
||||||
|
|
||||||
|
public string Name => "Hellion Chat - Sidebar active surface";
|
||||||
|
|
||||||
|
public SelfTestStepResult RunStep()
|
||||||
|
{
|
||||||
|
var sidebar = _plugin.MainWindow.GetSidebarForSelfTest();
|
||||||
|
if (sidebar is null)
|
||||||
|
{
|
||||||
|
ImGui.Text("Sidebar null");
|
||||||
|
SelfTestReport.Append(Name, "FAIL", new[] { "Sidebar null" });
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = NewProbe("Surface Probe A@SelfTest");
|
||||||
|
var b = NewProbe("Surface Probe B@SelfTest");
|
||||||
|
var list = new List<Tab> { a, b };
|
||||||
|
var width = (float)Plugin.Config.SidebarAutoSwitchThresholdPx + 100f;
|
||||||
|
var savedWidth = Plugin.Config.SidebarWidth;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Plugin.Config.SidebarWidth = 220;
|
||||||
|
|
||||||
|
// (a) one of two tabs is active -> exactly one surface
|
||||||
|
Tab? active = a;
|
||||||
|
sidebar.Draw(width, list, ref active);
|
||||||
|
if (sidebar.LastRenderedActiveSurfaceCount != 1)
|
||||||
|
return Fail(
|
||||||
|
$"active tab drew {sidebar.LastRenderedActiveSurfaceCount}, expected 1"
|
||||||
|
);
|
||||||
|
|
||||||
|
// (b) no active tab (every tab popped out) -> zero, not a crash
|
||||||
|
active = null;
|
||||||
|
sidebar.Draw(width, list, ref active);
|
||||||
|
if (sidebar.LastRenderedActiveSurfaceCount != 0)
|
||||||
|
return Fail(
|
||||||
|
$"null active drew {sidebar.LastRenderedActiveSurfaceCount}, expected 0"
|
||||||
|
);
|
||||||
|
|
||||||
|
// (c) icon-only mode still marks the active row
|
||||||
|
active = b;
|
||||||
|
sidebar.Draw((float)Plugin.Config.SidebarAutoSwitchThresholdPx - 1f, list, ref active);
|
||||||
|
if (sidebar.LastRenderedActiveSurfaceCount != 1)
|
||||||
|
return Fail($"icon-only drew {sidebar.LastRenderedActiveSurfaceCount}, expected 1");
|
||||||
|
|
||||||
|
SelfTestReport.Append(Name, "PASS", new[] { "1 / 0 / 1 across the three cases" });
|
||||||
|
return SelfTestStepResult.Pass;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Plugin.Config.SidebarWidth = savedWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Tab NewProbe(string name) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||||
|
{
|
||||||
|
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
private SelfTestStepResult Fail(string message)
|
||||||
|
{
|
||||||
|
ImGui.Text(message);
|
||||||
|
SelfTestReport.Append(Name, "FAIL", new[] { message });
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CleanUp() { }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user