Files
HellionChat/HellionChat/SelfTests/NotificationSoundSelectStep.cs
T

107 lines
4.1 KiB
C#

using Dalamud.Bindings.ImGui;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.SelfTest;
using HellionChat.Code;
using HellionChat.Util;
namespace HellionChat.SelfTests;
// B3-3: notification-sound selection. Drives the pure SelectNotificationSound
// (the exact pick logic ProcessMessage runs per message) through its SelfTest
// wrapper with local synthetic tabs — Plugin.Config.Tabs is never touched, so
// no real tab gains messages or unread state. The audible preview button is
// smoke-only and deliberately not exercised here.
internal sealed class NotificationSoundSelectStep : ISelfTestStep
{
public string Name => "Hellion Chat - Notification sound selection";
public SelfTestStepResult RunStep()
{
// Probe: a plain Say line, built the FakeMessage way (InputPreview /
// AutoTellTabsService pattern). Source 0 short-circuits the source
// filter in Message.Matches, so only the ChatType key decides a match.
var ss = new SeStringBuilder().AddText("probe").Build();
var chunks = ChunkUtil.ToChunks(ss, ChunkSource.Content, ChatType.Say).ToList();
var probe = Message.FakeMessage(chunks, new ChatCode(XivChatType.Say, 0, 0));
// The current tab wants a sound too — it must lose ONLY because it is
// current, so a broken is-active exclusion yields 1 instead of 7 here.
var currentTab = MakeSayTab(enableSound: true, soundId: 1);
var inactiveWanting = MakeSayTab(enableSound: true, soundId: 7);
// (a) the inactive tab that wants a sound wins.
var picked = MessageManager.TestSelectNotificationSoundForSelfTest(
[currentTab, inactiveWanting],
currentTab,
probe,
playSounds: true
);
if (picked != 7)
{
ImGui.Text($"Expected sound 7 from inactive tab, got {picked?.ToString() ?? "null"}");
return SelfTestStepResult.Fail;
}
// (b) first match wins: a later qualifying tab must not override.
var second = MakeSayTab(enableSound: true, soundId: 9);
picked = MessageManager.TestSelectNotificationSoundForSelfTest(
[currentTab, inactiveWanting, second],
currentTab,
probe,
playSounds: true
);
if (picked != 7)
{
ImGui.Text($"First-match guard broken: expected 7, got {picked?.ToString() ?? "null"}");
return SelfTestStepResult.Fail;
}
// (c) the global sound master mutes everything.
picked = MessageManager.TestSelectNotificationSoundForSelfTest(
[currentTab, inactiveWanting],
currentTab,
probe,
playSounds: false
);
if (picked is not null)
{
ImGui.Text($"PlaySounds=false must return null, got {picked}");
return SelfTestStepResult.Fail;
}
// (d) negative: a tab without the Say channel never matches the probe.
var nonMatching = new Tab { EnableNotificationSound = true, NotificationSoundId = 7 };
picked = MessageManager.TestSelectNotificationSoundForSelfTest(
[currentTab, nonMatching],
currentTab,
probe,
playSounds: true
);
if (picked is not null)
{
ImGui.Text($"Non-matching tab must not pick a sound, got {picked}");
return SelfTestStepResult.Fail;
}
return SelfTestStepResult.Pass;
}
// Local synthetic tab matching Say, the way TabsUtil presets build their
// channel maps. Non-temp and without TellTarget, so Tab.Matches stays on
// the pure channel path instead of routing through MatchesSender.
private static Tab MakeSayTab(bool enableSound, uint soundId) =>
new()
{
Name = "selftest-sound",
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
},
EnableNotificationSound = enableSound,
NotificationSoundId = soundId,
};
public void CleanUp() { }
}