acdream/tests/AcDream.UI.Abstractions.Tests/Panels/Chat/ChatVMLastTellSenderTests.cs
Erik f14296c75f feat(ui): #17 ChatPanel input field + slash commands + reply-to-last-tell
ChatPanel gains an Enter-to-submit input field via the I.1
InputTextSubmit widget. Submitted text routes through ChatInputParser
to a SendChatCmd published on ctx.Commands; LiveCommandBus (I.3)
handles the wire send + ChatLog echo.

Recognised prefixes (ported from holtburger commands.rs):

  /say msg or no prefix  -> Say
  /t Name msg or /tell   -> Tell  (first whitespace token = target)
  /r msg                 -> Tell  (target = LastIncomingTellSender)
  /g msg                 -> General
  /f msg                 -> Fellowship
  /a msg                 -> Allegiance
  /m msg                 -> Monarch
  /p msg                 -> Patron
  /v msg                 -> Vassals
  /cv msg                -> CoVassals
  /lfg msg               -> Lfg
  /trade msg             -> Trade
  /role msg              -> Roleplay
  /society msg           -> Society
  /olthoi msg            -> Olthoi

Edge cases: empty / whitespace / cmd-without-message / /r without
prior tell -> null (no-op). Unknown /xyz prefix -> Say with literal
text (matches holtburger's Talk(command) default arm).

ChatVM.LastIncomingTellSender populated only on incoming Tell entries;
discriminated by SenderGuid != 0 (OnSelfSent echoes always carry 0).

32 new tests:
- ChatInputParserTests: 22 covering every prefix + edge case
- ChatVMLastTellSenderTests: 6 covering capture + skip rules
- ChatPanelInputTests: 6 using FakePanelRenderer + recording
  ICommandBus to assert publish behaviour

UI.Abstractions.Tests: 60 -> 92. Solution total: 934 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 19:44:04 +02:00

82 lines
2.3 KiB
C#

using AcDream.Core.Chat;
using AcDream.UI.Abstractions.Panels.Chat;
namespace AcDream.UI.Abstractions.Tests.Panels.Chat;
/// <summary>
/// Phase I.4: <see cref="ChatVM.LastIncomingTellSender"/> tracks the
/// sender of the most recent INCOMING Tell so the chat panel can route
/// <c>/r</c> replies. Outgoing self-sent Tell echoes (which run through
/// <see cref="ChatLog.OnSelfSent"/> with <c>SenderGuid = 0</c>) must not
/// pollute the field.
/// </summary>
public sealed class ChatVMLastTellSenderTests
{
[Fact]
public void LastIncomingTellSender_StartsNull()
{
var log = new ChatLog();
var vm = new ChatVM(log);
Assert.Null(vm.LastIncomingTellSender);
}
[Fact]
public void LastIncomingTellSender_PopulatedFromOnTellReceived()
{
var log = new ChatLog();
var vm = new ChatVM(log);
log.OnTellReceived(sender: "Bestie", text: "ping", senderGuid: 0x5000_00AAu);
Assert.Equal("Bestie", vm.LastIncomingTellSender);
}
[Fact]
public void LastIncomingTellSender_UpdatedToMostRecentIncomingTell()
{
var log = new ChatLog();
var vm = new ChatVM(log);
log.OnTellReceived("Bestie", "ping", 0x5000_00AAu);
log.OnTellReceived("Regal", "yo", 0x5000_00BBu);
Assert.Equal("Regal", vm.LastIncomingTellSender);
}
[Fact]
public void LastIncomingTellSender_IgnoresSelfSentEcho()
{
var log = new ChatLog();
var vm = new ChatVM(log);
// /r reply echo: SenderGuid = 0 (no real GUID for ourselves).
// Must NOT clobber the captured sender.
log.OnTellReceived("Bestie", "ping", 0x5000_00AAu);
log.OnSelfSent(ChatKind.Tell, "back at you", targetOrChannel: "Bestie");
Assert.Equal("Bestie", vm.LastIncomingTellSender);
}
[Fact]
public void LastIncomingTellSender_IgnoresLocalSpeech()
{
var log = new ChatLog();
var vm = new ChatVM(log);
log.OnLocalSpeech("Caith", "hello", 0x5000_00CCu, isRanged: false);
Assert.Null(vm.LastIncomingTellSender);
}
[Fact]
public void LastIncomingTellSender_IgnoresChannelBroadcast()
{
var log = new ChatLog();
var vm = new ChatVM(log);
log.OnChannelBroadcast(channelId: 7, sender: "Caith", text: "raid time");
Assert.Null(vm.LastIncomingTellSender);
}
}