Files
HellionChat/HellionChat/SelfTests/PayloadHandlerCtorSmokeStep.cs
T

70 lines
2.8 KiB
C#

using Dalamud.Bindings.ImGui;
using Dalamud.Plugin.SelfTest;
namespace HellionChat.SelfTests;
// Drives the per-frame Lender<PayloadHandler> path the same way MainWindow.Draw
// and InputPreview do (Borrow() + ResetCounter()), NOT the eager singleton.
// PayloadHandler is registered twice (PluginHostFactory.cs:253/254): an eager
// singleton for the init HostedServices, and a Lender<T> factory-lambda for
// per-frame isolation. MS.DI resolves factory lambdas lazily and does not
// detect cycles through them, so a Borrow() that throws is the only automated
// signal of a broken lazy ctor before the first real frame renders. A
// singleton-only smoke would resolve the eager instance and mask exactly that
// failure. Resolve through the container/Lender, never new().
internal sealed class PayloadHandlerCtorSmokeStep : ISelfTestStep
{
private readonly Plugin plugin;
public PayloadHandlerCtorSmokeStep(Plugin plugin)
{
this.plugin = plugin;
}
public string Name => "Hellion Chat - PayloadHandler ctor smoke";
public SelfTestStepResult RunStep()
{
var lender = this.plugin.PayloadHandlerLender;
if (lender is null)
{
ImGui.Text("Plugin.PayloadHandlerLender is null");
return SelfTestStepResult.Fail;
}
// Borrow() runs MakePayloadHandler's factory lambda on first use; a
// throw or null here means a broken lazy ctor. This is the real
// per-frame construction path, not the eager singleton.
var borrowed = lender.Borrow();
// Keep the probe idempotent and avoid perturbing the frame path:
// MainWindow.Draw resets this same shared Lender every frame, so
// resetting here leaves a closed-MainWindow /xlperf run clean too.
lender.ResetCounter();
if (borrowed is null)
{
ImGui.Text("Lender<PayloadHandler>.Borrow() returned null");
return SelfTestStepResult.Fail;
}
// Second construction path: the eager singleton the init HostedServices
// consume (PluginHostFactory.cs:253, :356). Assert it resolved too.
if (this.plugin.PayloadHandler is null)
{
ImGui.Text("Plugin.PayloadHandler (singleton) is null");
return SelfTestStepResult.Fail;
}
// NOTE: we deliberately do NOT assert HandleTooltips == false /
// HoveredItem == 0u. MainWindow and InputPreview share this Lender, so a
// warm pool can hand back a reused instance whose hover state was set by
// a prior frame. The honest ctor-smoke assertion is "constructs through
// the real lazy path and is reachable" — a non-default warm value does
// not contradict that.
return SelfTestStepResult.Pass;
}
public void CleanUp() { }
}