Add channel management feature with public/private channels, membership (owner/member roles), invitations, broadcast messaging, and full MCP tool exposure. New files: - internal/channels/ - types, store, service, validation, errors - internal/mcp/channel_tools.go - 8 MCP tools for channel operations - schema/002_channels.sql - migration for channel_invites table MCP tools: create_channel, join_channel, leave_channel, list_channels, invite_to_channel, kick_from_channel, send_channel_message, update_channel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
70 lines
1.7 KiB
Go
70 lines
1.7 KiB
Go
package channels
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
func TestValidateChannelName(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
wantErr bool
|
|
}{
|
|
{"valid simple", "alerts", false},
|
|
{"valid with hyphens", "my-channel", false},
|
|
{"valid with underscores", "my_channel", false},
|
|
{"valid mixed", "my-channel_123", false},
|
|
{"valid single char", "a", false},
|
|
{"valid numbers", "123", false},
|
|
{"empty", "", true},
|
|
{"spaces", "my channel", true},
|
|
{"special chars", "ch@nnel!", true},
|
|
{"starts with hyphen", "-channel", true},
|
|
{"starts with underscore", "_channel", true},
|
|
{"unicode", "ch\u00e4nnel", true},
|
|
{"dot", "my.channel", true},
|
|
{"too long (65 chars)", "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffffggggg", true},
|
|
{"exactly 64 chars", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := ValidateChannelName(tt.input)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Error("expected error, got nil")
|
|
}
|
|
if !errors.Is(err, ErrInvalidChannelName) {
|
|
t.Errorf("expected ErrInvalidChannelName, got %v", err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalizeChannelName(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"alerts", "alerts"},
|
|
{"ALERTS", "alerts"},
|
|
{"MyChannel", "mychannel"},
|
|
{"Mixed-Case_123", "mixed-case_123"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
got := NormalizeChannelName(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("NormalizeChannelName(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|