fix(chat): #363 — retail 0x1A typing for command refusals via the interface-text seam
ChatVM gains an OnInterfaceText hook + ShowInterfaceText(text), the
App-layer composition wires it to RuntimeCommunicationState.AddText,
and ChatCommandRouter routes every retail-0x1A command refusal through
it instead of the chat log's 0x00 sink. UI.Abstractions still never
references Runtime directly; unwired hosts (headless, tests) fall back
to the chat log tagged ClientLocal so no text is ever silently lost.
Reclassified per register row AP-183 (DoChannelList/On/Off, DoAllegiance,
DoHouseAvailableList — the last also corrected to retail's own bad-house-
type string instead of a synthesized "Usage:" line) and newly wired two
sites that previously showed nothing at all (DoStupidChannelHack's bare
legacy-channel-verb refusal, DoReply's message-but-no-last-teller
refusal). The generic bad-args fallback now resolves WeenieErrorMessages
0x026 ("That is not a valid command.", retail's HandleFailureEvent(0x26))
instead of synthesizing "Usage: {Usage}". DoSpeaker/DoEndurance/DoTitle
are untouched — already correct at 0x00.
Also closes #367 (DoHelp's "Unknown command" fallback and the degenerate-
prefix refusal now reach the SpewBox too) and retires register row
AP-186, whose own filing proposed exactly this seam shape.
Full Release suite: 12,542 passed / 4 skipped / 0 failed (baseline
12,466/4/0 at ff2784ea).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff2784eaa4
commit
09453ecae8
14 changed files with 702 additions and 106 deletions
|
|
@ -423,4 +423,95 @@ public sealed class ChatInputParserTests
|
|||
Assert.Null(parsed.Value.TargetName);
|
||||
Assert.Equal(text, parsed.Value.Text);
|
||||
}
|
||||
|
||||
// ── Issue #363: IsBareRegisteredChannelVerb / IsReplyMissingLastTeller ──
|
||||
|
||||
[Theory]
|
||||
[InlineData("/g")]
|
||||
[InlineData("/f")]
|
||||
[InlineData("/fellow")]
|
||||
[InlineData("/fellows")]
|
||||
[InlineData("/fellowship")]
|
||||
[InlineData("/group")]
|
||||
[InlineData("/party")]
|
||||
[InlineData("/a")]
|
||||
[InlineData("/guild")]
|
||||
[InlineData("/gu")]
|
||||
[InlineData("/ab")]
|
||||
[InlineData("/m")]
|
||||
[InlineData("/monarch")]
|
||||
[InlineData("/p")]
|
||||
[InlineData("/patron")]
|
||||
[InlineData("/v")]
|
||||
[InlineData("/vassal")]
|
||||
[InlineData("/vassals")]
|
||||
[InlineData("/c")]
|
||||
[InlineData("/covassal")]
|
||||
[InlineData("/covassals")]
|
||||
[InlineData("/co-vassals")]
|
||||
public void IsBareRegisteredChannelVerb_TrueForEveryLegacyChannelAlias(string verb)
|
||||
{
|
||||
Assert.True(ChatInputParser.IsBareRegisteredChannelVerb(verb));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/general")]
|
||||
[InlineData("/cg")]
|
||||
[InlineData("/lfg")]
|
||||
[InlineData("/clfg")]
|
||||
[InlineData("/trade")]
|
||||
[InlineData("/ct")]
|
||||
[InlineData("/roleplay")]
|
||||
[InlineData("/crp")]
|
||||
[InlineData("/society")]
|
||||
[InlineData("/soc")]
|
||||
[InlineData("/olthoi")]
|
||||
[InlineData("/o")]
|
||||
public void IsBareRegisteredChannelVerb_FalseForTurbineOnlyChannels(string verb)
|
||||
{
|
||||
// The seven Turbine-only channels are never DoStupidChannelHack's
|
||||
// clients (command-registry doc §2.3).
|
||||
Assert.False(ChatInputParser.IsBareRegisteredChannelVerb(verb));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/g hi gang")]
|
||||
[InlineData("/a hey")]
|
||||
[InlineData("hello")]
|
||||
[InlineData("/say hi")]
|
||||
[InlineData("/r hi")]
|
||||
public void IsBareRegisteredChannelVerb_FalseWithMessageOrNotAChannelVerb(string input)
|
||||
{
|
||||
Assert.False(ChatInputParser.IsBareRegisteredChannelVerb(input));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/r hi there")]
|
||||
[InlineData("/reply hi there")]
|
||||
[InlineData("/rp hi there")]
|
||||
public void IsReplyMissingLastTeller_TrueWithMessageAndNoLastTeller(string input)
|
||||
{
|
||||
Assert.True(ChatInputParser.IsReplyMissingLastTeller(input, lastTellSender: null));
|
||||
Assert.True(ChatInputParser.IsReplyMissingLastTeller(input, lastTellSender: ""));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsReplyMissingLastTeller_FalseWhenLastTellerPresent()
|
||||
{
|
||||
Assert.False(ChatInputParser.IsReplyMissingLastTeller("/r hi there", lastTellSender: "Bestie"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/r")]
|
||||
[InlineData("/r ")]
|
||||
[InlineData("/g hi gang")]
|
||||
[InlineData("hello")]
|
||||
public void IsReplyMissingLastTeller_FalseWithoutAMessageOrNotAReplyVerb(string input)
|
||||
{
|
||||
// Bare "/r" (no message at all) is a DIFFERENT retail branch
|
||||
// (DoReply's own copy of the "you must specify text" string) and
|
||||
// is deliberately out of scope for this predicate — see its doc
|
||||
// comment.
|
||||
Assert.False(ChatInputParser.IsReplyMissingLastTeller(input, lastTellSender: null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue