mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
f8b656ec37
Add unified ShouldRespondInGroup to BaseChannel, replacing scattered per-channel group filtering logic. Introduce GroupTriggerConfig (with mention_only + prefixes), TypingConfig, and PlaceholderConfig types. Migrate Discord MentionOnly, OneBot checkGroupTrigger, and LINE hardcoded mention-only to the shared mechanism. Add group trigger entry points for Slack, Telegram, QQ, Feishu, DingTalk, and WeCom. Legacy config fields are preserved with automatic migration.
178 lines
4.6 KiB
Go
178 lines
4.6 KiB
Go
package channels
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/sipeed/picoclaw/pkg/config"
|
|
)
|
|
|
|
func TestBaseChannelIsAllowed(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
allowList []string
|
|
senderID string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty allowlist allows all",
|
|
allowList: nil,
|
|
senderID: "anyone",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "compound sender matches numeric allowlist",
|
|
allowList: []string{"123456"},
|
|
senderID: "123456|alice",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "compound sender matches username allowlist",
|
|
allowList: []string{"@alice"},
|
|
senderID: "123456|alice",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "numeric sender matches legacy compound allowlist",
|
|
allowList: []string{"123456|alice"},
|
|
senderID: "123456",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "non matching sender is denied",
|
|
allowList: []string{"123456"},
|
|
senderID: "654321|bob",
|
|
want: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ch := NewBaseChannel("test", nil, nil, tt.allowList)
|
|
if got := ch.IsAllowed(tt.senderID); got != tt.want {
|
|
t.Fatalf("IsAllowed(%q) = %v, want %v", tt.senderID, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldRespondInGroup(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
gt config.GroupTriggerConfig
|
|
isMentioned bool
|
|
content string
|
|
wantRespond bool
|
|
wantContent string
|
|
}{
|
|
{
|
|
name: "no config - permissive default",
|
|
gt: config.GroupTriggerConfig{},
|
|
isMentioned: false,
|
|
content: "hello world",
|
|
wantRespond: true,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "no config - mentioned",
|
|
gt: config.GroupTriggerConfig{},
|
|
isMentioned: true,
|
|
content: "hello world",
|
|
wantRespond: true,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "mention_only - not mentioned",
|
|
gt: config.GroupTriggerConfig{MentionOnly: true},
|
|
isMentioned: false,
|
|
content: "hello world",
|
|
wantRespond: false,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "mention_only - mentioned",
|
|
gt: config.GroupTriggerConfig{MentionOnly: true},
|
|
isMentioned: true,
|
|
content: "hello world",
|
|
wantRespond: true,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "prefix match",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"/ask"}},
|
|
isMentioned: false,
|
|
content: "/ask hello",
|
|
wantRespond: true,
|
|
wantContent: "hello",
|
|
},
|
|
{
|
|
name: "prefix no match - not mentioned",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"/ask"}},
|
|
isMentioned: false,
|
|
content: "hello world",
|
|
wantRespond: false,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "prefix no match - but mentioned",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"/ask"}},
|
|
isMentioned: true,
|
|
content: "hello world",
|
|
wantRespond: true,
|
|
wantContent: "hello world",
|
|
},
|
|
{
|
|
name: "multiple prefixes - second matches",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"/ask", "/bot"}},
|
|
isMentioned: false,
|
|
content: "/bot help me",
|
|
wantRespond: true,
|
|
wantContent: "help me",
|
|
},
|
|
{
|
|
name: "mention_only with prefixes - mentioned overrides",
|
|
gt: config.GroupTriggerConfig{MentionOnly: true, Prefixes: []string{"/ask"}},
|
|
isMentioned: true,
|
|
content: "hello",
|
|
wantRespond: true,
|
|
wantContent: "hello",
|
|
},
|
|
{
|
|
name: "mention_only with prefixes - not mentioned, no prefix",
|
|
gt: config.GroupTriggerConfig{MentionOnly: true, Prefixes: []string{"/ask"}},
|
|
isMentioned: false,
|
|
content: "hello",
|
|
wantRespond: false,
|
|
wantContent: "hello",
|
|
},
|
|
{
|
|
name: "empty prefix in list is skipped",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"", "/ask"}},
|
|
isMentioned: false,
|
|
content: "/ask test",
|
|
wantRespond: true,
|
|
wantContent: "test",
|
|
},
|
|
{
|
|
name: "prefix strips leading whitespace after prefix",
|
|
gt: config.GroupTriggerConfig{Prefixes: []string{"/ask "}},
|
|
isMentioned: false,
|
|
content: "/ask hello",
|
|
wantRespond: true,
|
|
wantContent: "hello",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ch := NewBaseChannel("test", nil, nil, nil, WithGroupTrigger(tt.gt))
|
|
gotRespond, gotContent := ch.ShouldRespondInGroup(tt.isMentioned, tt.content)
|
|
if gotRespond != tt.wantRespond {
|
|
t.Errorf("ShouldRespondInGroup() respond = %v, want %v", gotRespond, tt.wantRespond)
|
|
}
|
|
if gotContent != tt.wantContent {
|
|
t.Errorf("ShouldRespondInGroup() content = %q, want %q", gotContent, tt.wantContent)
|
|
}
|
|
})
|
|
}
|
|
}
|