butterrobot/internal/plugin/help/help_test.go

206 lines
5.6 KiB
Go

package help
import (
"strings"
"testing"
"git.nakama.town/fmartingr/butterrobot/internal/db"
"git.nakama.town/fmartingr/butterrobot/internal/model"
"git.nakama.town/fmartingr/butterrobot/internal/plugin"
)
// MockPlugin implements the Plugin interface for testing
type MockPlugin struct {
id string
name string
help string
}
func (m *MockPlugin) GetID() string { return m.id }
func (m *MockPlugin) GetName() string { return m.name }
func (m *MockPlugin) GetHelp() string { return m.help }
func (m *MockPlugin) RequiresConfig() bool {
return false
}
func (m *MockPlugin) OnMessage(msg *model.Message, config map[string]interface{}, cache model.CacheInterface) []*model.MessageAction {
return nil
}
// MockDatabase implements the ChannelPluginGetter interface for testing
type MockDatabase struct {
channelPlugins map[int64][]*model.ChannelPlugin
platformChannelPlugins map[string][]*model.ChannelPlugin // key: "platform:platformChannelID"
}
func (m *MockDatabase) GetChannelPlugins(channelID int64) ([]*model.ChannelPlugin, error) {
if plugins, exists := m.channelPlugins[channelID]; exists {
return plugins, nil
}
return nil, db.ErrNotFound
}
func (m *MockDatabase) GetChannelPluginsFromPlatformID(platform, platformChannelID string) ([]*model.ChannelPlugin, error) {
key := platform + ":" + platformChannelID
if plugins, exists := m.platformChannelPlugins[key]; exists {
return plugins, nil
}
return nil, db.ErrNotFound
}
func TestHelpPlugin_OnMessage(t *testing.T) {
tests := []struct {
name string
messageText string
enabledPlugins map[string]*MockPlugin
expectResponse bool
expectNoPlugins bool
expectCategories []string
}{
{
name: "responds to !help command",
messageText: "!help",
enabledPlugins: map[string]*MockPlugin{
"dev.ping": {
id: "dev.ping",
name: "Ping",
help: "Responds to 'ping' with 'pong'",
},
"fun.dice": {
id: "fun.dice",
name: "Dice Roller",
help: "Rolls dice when you type '!dice [formula]'",
},
},
expectResponse: true,
expectCategories: []string{"Development", "Fun and Entertainment"},
},
{
name: "ignores non-help messages",
messageText: "hello world",
enabledPlugins: map[string]*MockPlugin{},
expectResponse: false,
},
{
name: "ignores case variation",
messageText: "!HELP",
enabledPlugins: map[string]*MockPlugin{},
expectResponse: true,
expectNoPlugins: true,
},
{
name: "handles no enabled plugins",
messageText: "!help",
enabledPlugins: map[string]*MockPlugin{},
expectResponse: true,
expectNoPlugins: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create mock database
mockDB := &MockDatabase{
channelPlugins: make(map[int64][]*model.ChannelPlugin),
platformChannelPlugins: make(map[string][]*model.ChannelPlugin),
}
// Setup channel plugins in mock database
var channelPluginList []*model.ChannelPlugin
pluginCounter := int64(1)
for pluginID := range tt.enabledPlugins {
channelPluginList = append(channelPluginList, &model.ChannelPlugin{
ID: pluginCounter,
ChannelID: 1,
PluginID: pluginID,
Enabled: true,
Config: make(map[string]interface{}),
})
pluginCounter++
}
// Set up both mapping approaches for the test
mockDB.channelPlugins[1] = channelPluginList
mockDB.platformChannelPlugins["test:test-channel"] = channelPluginList
// Create help plugin
p := New(mockDB)
// Create mock channel
channel := &model.Channel{
ID: 1,
Platform: "test",
PlatformChannelID: "test-channel",
}
// Create test message
msg := &model.Message{
ID: "test-msg",
Text: tt.messageText,
Chat: "test-chat",
Channel: channel,
}
// Mock the plugin registry
originalRegistry := plugin.GetAvailablePlugins()
// Override the registry for this test
plugin.ClearRegistry()
for _, mockPlugin := range tt.enabledPlugins {
plugin.Register(mockPlugin)
}
// Call OnMessage
actions := p.OnMessage(msg, map[string]interface{}{}, nil)
// Restore original registry
plugin.ClearRegistry()
for _, p := range originalRegistry {
plugin.Register(p)
}
if !tt.expectResponse {
if len(actions) != 0 {
t.Errorf("Expected no response, but got %d actions", len(actions))
}
return
}
if len(actions) != 1 {
t.Errorf("Expected 1 action, got %d", len(actions))
return
}
action := actions[0]
if action.Type != model.ActionSendMessage {
t.Errorf("Expected ActionSendMessage, got %v", action.Type)
return
}
responseText := action.Message.Text
if tt.expectNoPlugins {
if !strings.Contains(responseText, "No plugins are currently enabled") {
t.Errorf("Expected 'no plugins' message, got: %s", responseText)
}
return
}
// Check that expected categories appear in response
for _, category := range tt.expectCategories {
if !strings.Contains(responseText, "**"+category+":**") {
t.Errorf("Expected category '%s' in response, got: %s", category, responseText)
}
}
// Check that plugin names and help text appear
for _, mockPlugin := range tt.enabledPlugins {
if !strings.Contains(responseText, mockPlugin.GetName()) {
t.Errorf("Expected plugin name '%s' in response", mockPlugin.GetName())
}
if !strings.Contains(responseText, mockPlugin.GetHelp()) {
t.Errorf("Expected plugin help '%s' in response", mockPlugin.GetHelp())
}
}
})
}
}