A comment that reads "MUST stay in lockstep with TryGetActiveCrossfade (K8)" helps nobody outside the plan that used to have a K8 in it, and the plans are not in this repo. Same for "Spec FR-4", "plan §B.2", "Sub-Task 4.4" and the F/R/M/A/S round codes scattered through the style engine and the self-tests. Personal names go too. "tester feedback from Jin (v1.4.7)" and "Flo decision 2026-06-15" carry the reason fine without naming anyone -- the version and the reason are the parts a reader can act on, and a public repo should not need a cast list to be read. The rule applied throughout: keep the why, drop the reference. Version numbers stay, since those resolve through the changelog. 77 files. ChunkUtil also carried 281 lines of commented-out code -- an older ToChunks variant and two helpers with no callers, inherited and never removed. Deleted; git remembers them.
150 lines
6.1 KiB
C#
150 lines
6.1 KiB
C#
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Game.Text.SeStringHandling;
|
|
using Dalamud.Plugin.SelfTest;
|
|
using HellionChat.Code;
|
|
using HellionChat.GameFunctions.Types;
|
|
using HellionChat.Util;
|
|
|
|
namespace HellionChat.SelfTests;
|
|
|
|
// The activation strip. Drives the REAL OnTabActivated -- the entry the
|
|
// Sidebar/TopTabBar click handlers, the pop-out path and the Draw-seed all call
|
|
// — with local probe tabs (Plugin.Config.Tabs is never touched). Asserts the
|
|
// five contracts: strip-on-switch, no-strip-on-reclick (TR-4), leg1 preserve,
|
|
// derive, and non-tell untouched.
|
|
internal sealed class TellResetOnActivateStep : ISelfTestStep
|
|
{
|
|
public string Name => "Hellion Chat - Tell reset on tab activate";
|
|
|
|
public SelfTestStepResult RunStep()
|
|
{
|
|
var other = MakeSayTab();
|
|
|
|
// (a) switching ONTO a stale-tell tab with no Tab-level binding strips the
|
|
// runtime tell state (target + partner label) and re-derives the channel.
|
|
var stale = MakeStaleTellTab(boundTellTarget: false, withLabel: true);
|
|
TabLifecycleHelpers.OnTabActivated(stale, other);
|
|
if (stale.CurrentChannel.TellTarget is not null)
|
|
{
|
|
ImGui.Text("(a) stale tell target not cleared on switch");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
if (stale.CurrentChannel.Channel != InputChannel.Say)
|
|
{
|
|
ImGui.Text($"(a) channel not re-derived to Say, got {stale.CurrentChannel.Channel}");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
if (stale.CurrentChannel.Name.Count != 0)
|
|
{
|
|
ImGui.Text("(a) stale partner label not cleared");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
// (b) re-clicking the already-active tab (previous == tab) must NOT strip
|
|
// a live game-tell conversation (TR-4 regression guard).
|
|
var reclick = MakeStaleTellTab(boundTellTarget: false, withLabel: false);
|
|
TabLifecycleHelpers.OnTabActivated(reclick, reclick);
|
|
if (reclick.CurrentChannel.TellTarget is null)
|
|
{
|
|
ImGui.Text("(b) re-click wrongly stripped the active tell tab");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
if (reclick.CurrentChannel.Channel != InputChannel.Tell)
|
|
{
|
|
ImGui.Text("(b) re-click wrongly changed the active tab's channel");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
// (c) a tab whose own Tab.TellTarget is set is a real binding (leg1):
|
|
// channel + runtime target survive a switch.
|
|
var bound = MakeStaleTellTab(boundTellTarget: true, withLabel: false);
|
|
TabLifecycleHelpers.OnTabActivated(bound, other);
|
|
if (bound.CurrentChannel.TellTarget is null)
|
|
{
|
|
ImGui.Text("(c) bound tell tab wrongly stripped");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
if (bound.CurrentChannel.Channel != InputChannel.Tell)
|
|
{
|
|
ImGui.Text("(c) bound tell tab channel wrongly changed");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
// (d) an Invalid-channel tab just derives (pre-existing semantics).
|
|
var invalid = MakeSayTab();
|
|
TabLifecycleHelpers.OnTabActivated(invalid, other);
|
|
if (invalid.CurrentChannel.Channel != InputChannel.Say)
|
|
{
|
|
ImGui.Text(
|
|
$"(d) invalid-channel tab not derived, got {invalid.CurrentChannel.Channel}"
|
|
);
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
// (e) a non-tell tab is left untouched. Seed it with runtime tell state
|
|
// AND a label so a guard that wrongly fired on non-tell tabs would null
|
|
// them — the channel re-derive alone could not mask that regression.
|
|
var say = MakeSayTab();
|
|
say.CurrentChannel.SetChannel(InputChannel.Say);
|
|
say.CurrentChannel.TellTarget = new TellTarget("Untouched", 21, 0, TellReason.Direct);
|
|
var sayLabel = new SeStringBuilder().AddText("Untouched@World").Build();
|
|
say.CurrentChannel.Name = ChunkUtil
|
|
.ToChunks(sayLabel, ChunkSource.Content, ChatType.Say)
|
|
.ToList();
|
|
TabLifecycleHelpers.OnTabActivated(say, other);
|
|
if (say.CurrentChannel.Channel != InputChannel.Say)
|
|
{
|
|
ImGui.Text("(e) non-tell tab channel wrongly changed");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
if (say.CurrentChannel.TellTarget is null || say.CurrentChannel.Name.Count == 0)
|
|
{
|
|
ImGui.Text("(e) non-tell tab runtime state wrongly stripped");
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
return SelfTestStepResult.Pass;
|
|
}
|
|
|
|
// A tab carrying runtime tell state the way the game-side detour leaves it:
|
|
// CurrentChannel.Channel == Tell with a resolvable CurrentChannel.TellTarget,
|
|
// optionally with the partner-name label chunks. boundTellTarget controls
|
|
// whether the Tab-level TellTarget marks it a real binding (leg1).
|
|
private static Tab MakeStaleTellTab(bool boundTellTarget, bool withLabel)
|
|
{
|
|
var tab = new Tab
|
|
{
|
|
Name = "selftest-activate-tell",
|
|
TellTarget = boundTellTarget
|
|
? new TellTarget("Bound", 21, 0, TellReason.Direct)
|
|
: TellTarget.Empty(),
|
|
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
|
{
|
|
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
|
|
},
|
|
};
|
|
tab.CurrentChannel.SetChannel(InputChannel.Tell);
|
|
tab.CurrentChannel.TellTarget = new TellTarget("Stale", 21, 0, TellReason.Direct);
|
|
if (withLabel)
|
|
{
|
|
var ss = new SeStringBuilder().AddText("Stale@World").Build();
|
|
tab.CurrentChannel.Name = ChunkUtil
|
|
.ToChunks(ss, ChunkSource.Content, ChatType.Say)
|
|
.ToList();
|
|
}
|
|
return tab;
|
|
}
|
|
|
|
private static Tab MakeSayTab() =>
|
|
new()
|
|
{
|
|
Name = "selftest-activate-say",
|
|
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
|
{
|
|
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
|
|
},
|
|
};
|
|
|
|
public void CleanUp() { }
|
|
}
|