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 false;
|
||||||
return true;
|
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.Bindings.ImGui;
|
||||||
using Dalamud.Plugin.SelfTest;
|
using Dalamud.Plugin.SelfTest;
|
||||||
|
using HellionChat.Integrations;
|
||||||
|
|
||||||
namespace HellionChat.SelfTests;
|
namespace HellionChat.SelfTests;
|
||||||
|
|
||||||
@@ -20,8 +21,26 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
|||||||
|
|
||||||
public string Name => "Hellion Chat - HonorificHeader render";
|
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()
|
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();
|
var header = plugin.MainWindow.GetHonorificHeaderForSelfTest();
|
||||||
if (header is null)
|
if (header is null)
|
||||||
{
|
{
|
||||||
@@ -29,9 +48,48 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
|||||||
return SelfTestStepResult.Fail;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
// (a) available + valid title + toggle on -> title renders
|
||||||
|
Plugin.Config.ShowHonorificTitleInHeader = true;
|
||||||
|
_svc.TestOnly_SetState(true, (3, 1), valid);
|
||||||
header.Draw(420f);
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -42,5 +100,12 @@ internal sealed class HonorificHeaderRenderStep : ISelfTestStep
|
|||||||
return SelfTestStepResult.Pass;
|
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
|
## Anti-pattern of record
|
||||||
|
|
||||||
`HonorificService.ShouldRenderSlot` had zero production callers and was green
|
`HonorificService.ShouldRenderSlot` once had zero production callers and was
|
||||||
only because the test called it directly — a test passing on a path the game
|
green only because the test called it directly — a test passing on a path the
|
||||||
never runs. That is the failure this standard prevents.
|
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
|
## Step classification
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user