test(honorific): assert the title gate through the real draw path
This commit is contained in:
@@ -195,4 +195,23 @@ internal sealed class HonorificService : IDisposable
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test seam: the three status fields are private-set and IPC-driven, which a
|
||||
// headless /xlperf run can't reach (Honorific is usually absent in tests).
|
||||
// Callers MUST snapshot the prior values and restore them in CleanUp, and
|
||||
// MUST drive Set -> Draw -> Assert within ONE synchronous RunStep (never
|
||||
// Waiting between Set and Assert) — a between-frame OnReady/OnTitleChanged
|
||||
// would otherwise clobber this state and a CleanUp restore can't un-corrupt a
|
||||
// mid-flight assertion. (A FontsReady precondition gate returning Waiting
|
||||
// BEFORE the snapshot/Set is fine — nothing is mutated yet.)
|
||||
internal void TestOnly_SetState(
|
||||
bool isAvailable,
|
||||
(uint Major, uint Minor)? detectedApiVersion,
|
||||
HonorificTitleData? title
|
||||
)
|
||||
{
|
||||
IsAvailable = isAvailable;
|
||||
DetectedApiVersion = detectedApiVersion;
|
||||
CurrentTitle = title;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.SelfTest;
|
||||
using HellionChat.Integrations;
|
||||
|
||||
namespace HellionChat.SelfTests;
|
||||
|
||||
@@ -20,8 +21,26 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
||||
|
||||
public string Name => "Hellion Chat - HonorificHeader render";
|
||||
|
||||
private HonorificService? _svc;
|
||||
private bool _prevAvailable;
|
||||
private (uint Major, uint Minor)? _prevVersion;
|
||||
private HonorificTitleData? _prevTitle;
|
||||
private bool _prevToggle;
|
||||
private bool _snapshotted;
|
||||
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
// HonorificHeader.Draw early-returns on !FontsReady (HonorificHeader.cs:40-44)
|
||||
// and never reaches the gated title branch, which would make assert (a) a
|
||||
// false FAIL during a font-atlas rebuild. Return Waiting BEFORE any
|
||||
// snapshot/mutation so the runner re-polls cleanly and no seam state leaks
|
||||
// (precedent: FoxBannerTextureSmokeStep). This is a pre-Set precondition
|
||||
// gate, not a mid-test Waiting — the Set->Draw->Assert window stays synchronous.
|
||||
if (!plugin.FontManager.FontsReady)
|
||||
{
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
var header = plugin.MainWindow.GetHonorificHeaderForSelfTest();
|
||||
if (header is null)
|
||||
{
|
||||
@@ -29,9 +48,48 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
_svc = header.GetServiceForSelfTest();
|
||||
_prevAvailable = _svc.IsAvailable;
|
||||
_prevVersion = _svc.DetectedApiVersion;
|
||||
_prevTitle = _svc.CurrentTitle;
|
||||
_prevToggle = Plugin.Config.ShowHonorificTitleInHeader;
|
||||
_snapshotted = true;
|
||||
|
||||
var valid = new HonorificTitleData("Champion", false, false, null, null, null, null, null);
|
||||
var original = new HonorificTitleData("Champion", false, true, null, null, null, null, null);
|
||||
|
||||
// Draw at a deliberately wide 420px so the title never hits the truncation
|
||||
// clamp — LastTitleRendered then reflects the GATE outcome, not the width.
|
||||
try
|
||||
{
|
||||
// (a) available + valid title + toggle on -> title renders
|
||||
Plugin.Config.ShowHonorificTitleInHeader = true;
|
||||
_svc.TestOnly_SetState(true, (3, 1), valid);
|
||||
header.Draw(420f);
|
||||
if (!header.LastTitleRendered)
|
||||
{
|
||||
ImGui.Text("Gate failed: valid title did not render");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
// (b) toggle off -> title suppressed (crown stays, untestable headless)
|
||||
Plugin.Config.ShowHonorificTitleInHeader = false;
|
||||
header.Draw(420f);
|
||||
if (header.LastTitleRendered)
|
||||
{
|
||||
ImGui.Text("Gate failed: title rendered with toggle off");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
// (c) IsOriginal title -> suppressed even with toggle on
|
||||
Plugin.Config.ShowHonorificTitleInHeader = true;
|
||||
_svc.TestOnly_SetState(true, (3, 1), original);
|
||||
header.Draw(420f);
|
||||
if (header.LastTitleRendered)
|
||||
{
|
||||
ImGui.Text("Gate failed: original title rendered");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -42,5 +100,12 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
public void CleanUp() { }
|
||||
public void CleanUp()
|
||||
{
|
||||
if (!_snapshotted || _svc is null)
|
||||
return;
|
||||
Plugin.Config.ShowHonorificTitleInHeader = _prevToggle;
|
||||
_svc.TestOnly_SetState(_prevAvailable, _prevVersion, _prevTitle);
|
||||
_snapshotted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,12 @@ step explicitly as smoke-only instead of faking a headless pass.
|
||||
|
||||
## Anti-pattern of record
|
||||
|
||||
`HonorificService.ShouldRenderSlot` had zero production callers and was green
|
||||
only because the test called it directly — a test passing on a path the game
|
||||
never runs. That is the failure this standard prevents.
|
||||
`HonorificService.ShouldRenderSlot` once had zero production callers and was
|
||||
green only because the test called it directly — a test passing on a path the
|
||||
game never runs. v1.8.7 retired it: the gate is now wired into the real
|
||||
`HonorificHeader.Draw` and asserted through it via
|
||||
`HonorificHeader.LastTitleRendered` (see `HonorificHeaderRenderStep`). Kept here
|
||||
as the canonical example of the failure this standard prevents.
|
||||
|
||||
## Step classification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user