test: tests para comandos sin prefijo
Tests del parser (pkg/message/parse_test.go): - Con prefijo !: comando estandar, con args, sin prefijo no detecta, lowercase - Sin prefijo: comando bare, con args, ! retrocompatible, primer token, lowercase - Casos borde: mensaje vacio, solo espacios, solo "!" - Retrocompatibilidad: "!help" con prefix="" produce mismo resultado que con "!" - Deteccion de menciones independiente del modo de prefijo Tests del robot (agents/robot_test.go): - !help muestra comandos sin ! cuando command_prefix es "" - Comandos custom en modo sin prefijo - Mismo conjunto de built-ins en ambos modos - newTestRobot ahora configura command_prefix: "!" explicitamente
This commit is contained in:
+81
-1
@@ -14,8 +14,20 @@ import (
|
||||
)
|
||||
|
||||
// newTestRobot creates a minimal Robot for testing without requiring
|
||||
// Matrix or network. Fields are initialized directly.
|
||||
// Matrix or network. Fields are initialized directly. Uses standard "!" prefix.
|
||||
func newTestRobot(t *testing.T) *Robot {
|
||||
t.Helper()
|
||||
return newTestRobotWithPrefix(t, "!")
|
||||
}
|
||||
|
||||
// newTestRobotNoPrefix creates a minimal Robot with command_prefix: "" (no prefix).
|
||||
func newTestRobotNoPrefix(t *testing.T) *Robot {
|
||||
t.Helper()
|
||||
return newTestRobotWithPrefix(t, "")
|
||||
}
|
||||
|
||||
// newTestRobotWithPrefix creates a Robot with the given command prefix.
|
||||
func newTestRobotWithPrefix(t *testing.T, prefix string) *Robot {
|
||||
t.Helper()
|
||||
cfg := &config.AgentConfig{
|
||||
Agent: config.AgentMeta{
|
||||
@@ -25,6 +37,11 @@ func newTestRobot(t *testing.T) *Robot {
|
||||
Description: "robot for tests",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Matrix: config.MatrixCfg{
|
||||
Filters: config.FiltersCfg{
|
||||
CommandPrefix: prefix,
|
||||
},
|
||||
},
|
||||
}
|
||||
r := &Robot{
|
||||
cfg: cfg,
|
||||
@@ -288,3 +305,66 @@ func TestRobotBuiltinCommandCount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── No-prefix command tests ───────────────────────────────────────────────
|
||||
|
||||
// TestRobotNoPrefixCmdHelp verifies that help shows commands without ! prefix
|
||||
// when command_prefix is "".
|
||||
func TestRobotNoPrefixCmdHelp(t *testing.T) {
|
||||
r := newTestRobotNoPrefix(t)
|
||||
|
||||
reply := r.cmdHelp(context.Background(), decision.MessageContext{})
|
||||
|
||||
if !strings.Contains(reply, "Comandos disponibles") {
|
||||
t.Error("help reply missing header")
|
||||
}
|
||||
|
||||
// Commands should appear WITHOUT ! prefix
|
||||
for _, cmd := range []string{"help", "ping", "status", "info", "version"} {
|
||||
// Should contain the command name
|
||||
if !strings.Contains(reply, cmd) {
|
||||
t.Errorf("help reply missing command %s", cmd)
|
||||
}
|
||||
// Should NOT contain "!cmd" as usage (but might contain it elsewhere)
|
||||
if strings.Contains(reply, "!"+cmd) {
|
||||
t.Errorf("help reply should not show !%s in no-prefix mode", cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRobotNoPrefixCmdHelpWithCustom verifies custom commands in no-prefix mode.
|
||||
func TestRobotNoPrefixCmdHelpWithCustom(t *testing.T) {
|
||||
r := newTestRobotNoPrefix(t)
|
||||
|
||||
r.RegisterCommand(
|
||||
command.Spec{Name: "deploy", Description: "Deploy to env", Usage: "deploy <env>"},
|
||||
func(_ context.Context, _ decision.MessageContext) string { return "deployed" },
|
||||
)
|
||||
|
||||
reply := r.cmdHelp(context.Background(), decision.MessageContext{})
|
||||
|
||||
if !strings.Contains(reply, "Comandos del robot") {
|
||||
t.Error("help reply missing 'Comandos del robot' section")
|
||||
}
|
||||
if !strings.Contains(reply, "deploy") {
|
||||
t.Error("help reply missing custom command deploy")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRobotNoPrefixSameBuiltins verifies that no-prefix robots have the
|
||||
// same set of built-in commands as standard robots.
|
||||
func TestRobotNoPrefixSameBuiltins(t *testing.T) {
|
||||
standard := newTestRobot(t)
|
||||
noPrefix := newTestRobotNoPrefix(t)
|
||||
|
||||
if len(standard.commands) != len(noPrefix.commands) {
|
||||
t.Errorf("command count mismatch: standard=%d, noPrefix=%d",
|
||||
len(standard.commands), len(noPrefix.commands))
|
||||
}
|
||||
|
||||
for name := range standard.commands {
|
||||
if _, ok := noPrefix.commands[name]; !ok {
|
||||
t.Errorf("no-prefix robot missing command %q", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package message
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse_CommandWithPrefix(t *testing.T) {
|
||||
opts := ParseOptions{
|
||||
CommandPrefix: "!",
|
||||
BotUserID: "@bot:server",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
wantCmd string
|
||||
wantArgs []string
|
||||
}{
|
||||
{
|
||||
name: "standard command",
|
||||
body: "!help",
|
||||
wantCmd: "help",
|
||||
},
|
||||
{
|
||||
name: "command with args",
|
||||
body: "!deploy prod",
|
||||
wantCmd: "deploy",
|
||||
wantArgs: []string{"prod"},
|
||||
},
|
||||
{
|
||||
name: "no prefix means no command",
|
||||
body: "help",
|
||||
wantCmd: "",
|
||||
},
|
||||
{
|
||||
name: "normal message",
|
||||
body: "hola mundo",
|
||||
wantCmd: "",
|
||||
},
|
||||
{
|
||||
name: "command is lowercased",
|
||||
body: "!HELP",
|
||||
wantCmd: "help",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
|
||||
if ctx.Command != tt.wantCmd {
|
||||
t.Errorf("Command = %q, want %q", ctx.Command, tt.wantCmd)
|
||||
}
|
||||
if tt.wantArgs != nil {
|
||||
if len(ctx.Args) != len(tt.wantArgs) {
|
||||
t.Errorf("Args = %v, want %v", ctx.Args, tt.wantArgs)
|
||||
}
|
||||
for i, arg := range tt.wantArgs {
|
||||
if i < len(ctx.Args) && ctx.Args[i] != arg {
|
||||
t.Errorf("Args[%d] = %q, want %q", i, ctx.Args[i], arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_CommandWithoutPrefix(t *testing.T) {
|
||||
opts := ParseOptions{
|
||||
CommandPrefix: "",
|
||||
BotUserID: "@bot:server",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
wantCmd string
|
||||
wantArgs []string
|
||||
}{
|
||||
{
|
||||
name: "bare command",
|
||||
body: "help",
|
||||
wantCmd: "help",
|
||||
},
|
||||
{
|
||||
name: "bare command with args",
|
||||
body: "deploy prod",
|
||||
wantCmd: "deploy",
|
||||
wantArgs: []string{"prod"},
|
||||
},
|
||||
{
|
||||
name: "bang prefix stripped for backward compatibility",
|
||||
body: "!help",
|
||||
wantCmd: "help",
|
||||
},
|
||||
{
|
||||
name: "bang prefix stripped with args",
|
||||
body: "!deploy staging",
|
||||
wantCmd: "deploy",
|
||||
wantArgs: []string{"staging"},
|
||||
},
|
||||
{
|
||||
name: "first token is command",
|
||||
body: "hola mundo",
|
||||
wantCmd: "hola",
|
||||
wantArgs: []string{"mundo"},
|
||||
},
|
||||
{
|
||||
name: "command is lowercased",
|
||||
body: "HELP",
|
||||
wantCmd: "help",
|
||||
},
|
||||
{
|
||||
name: "bang-only message produces no command",
|
||||
body: "!",
|
||||
wantCmd: "",
|
||||
},
|
||||
{
|
||||
name: "empty message",
|
||||
body: "",
|
||||
wantCmd: "",
|
||||
},
|
||||
{
|
||||
name: "whitespace-only message",
|
||||
body: " ",
|
||||
wantCmd: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
|
||||
if ctx.Command != tt.wantCmd {
|
||||
t.Errorf("Command = %q, want %q", ctx.Command, tt.wantCmd)
|
||||
}
|
||||
if tt.wantArgs != nil {
|
||||
if len(ctx.Args) != len(tt.wantArgs) {
|
||||
t.Errorf("Args = %v, want %v", ctx.Args, tt.wantArgs)
|
||||
}
|
||||
for i, arg := range tt.wantArgs {
|
||||
if i < len(ctx.Args) && ctx.Args[i] != arg {
|
||||
t.Errorf("Args[%d] = %q, want %q", i, ctx.Args[i], arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_MentionDetection(t *testing.T) {
|
||||
// Ensure mention detection still works regardless of command prefix mode.
|
||||
botUID := "@bot:server"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
mentions []string
|
||||
wantMention bool
|
||||
}{
|
||||
{
|
||||
name: "mentioned via m.mentions",
|
||||
body: "hello",
|
||||
mentions: []string{botUID},
|
||||
wantMention: true,
|
||||
},
|
||||
{
|
||||
name: "mentioned via body text",
|
||||
body: "hey @bot:server what's up",
|
||||
wantMention: true,
|
||||
},
|
||||
{
|
||||
name: "not mentioned",
|
||||
body: "hello world",
|
||||
wantMention: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
opts := ParseOptions{
|
||||
CommandPrefix: "!",
|
||||
BotUserID: botUID,
|
||||
MentionedUserIDs: tt.mentions,
|
||||
}
|
||||
ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
|
||||
if ctx.IsMention != tt.wantMention {
|
||||
t.Errorf("IsMention = %v, want %v", ctx.IsMention, tt.wantMention)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse_NoPrefixBackwardCompatibility(t *testing.T) {
|
||||
// Regression: when prefix is "" and user sends "!help", the result should be
|
||||
// identical to when prefix is "!" and user sends "!help".
|
||||
prefixed := Parse("!help", "@user:server", "!room:server", 0, false, ParseOptions{
|
||||
CommandPrefix: "!",
|
||||
BotUserID: "@bot:server",
|
||||
})
|
||||
noPrefix := Parse("!help", "@user:server", "!room:server", 0, false, ParseOptions{
|
||||
CommandPrefix: "",
|
||||
BotUserID: "@bot:server",
|
||||
})
|
||||
|
||||
if prefixed.Command != noPrefix.Command {
|
||||
t.Errorf("Command mismatch: prefixed=%q, noPrefix=%q", prefixed.Command, noPrefix.Command)
|
||||
}
|
||||
if len(prefixed.Args) != len(noPrefix.Args) {
|
||||
t.Errorf("Args length mismatch: prefixed=%v, noPrefix=%v", prefixed.Args, noPrefix.Args)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user