package vk import ( "encoding/json" "testing" "github.com/sipeed/picoclaw/pkg/bus" "github.com/sipeed/picoclaw/pkg/channels" "github.com/sipeed/picoclaw/pkg/config" ) func makeVKTestBaseChannel(vkCfg config.VKSettings) *config.Channel { settings, _ := json.Marshal(vkCfg) return &config.Channel{ Enabled: true, Type: config.ChannelVK, Settings: settings, } } func TestNewVKChannel(t *testing.T) { msgBus := bus.NewMessageBus() t.Run("missing group_id", func(t *testing.T) { bc := makeVKTestBaseChannel(config.VKSettings{ Token: *config.NewSecureString("test_token"), }) ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error during creation: %v", err) } if ch.Name() != "vk" { t.Errorf("Name() = %q, want %q", ch.Name(), "vk") } if ch.IsRunning() { t.Error("new channel should not be running") } }) t.Run("valid config with group_id", func(t *testing.T) { bc := makeVKTestBaseChannel(config.VKSettings{ Token: *config.NewSecureString("test_token"), GroupID: 123456789, }) ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error: %v", err) } if ch.Name() != "vk" { t.Errorf("Name() = %q, want %q", ch.Name(), "vk") } if ch.IsRunning() { t.Error("new channel should not be running") } }) t.Run("with allow_from", func(t *testing.T) { vkCfg := config.VKSettings{ Token: *config.NewSecureString("test_token"), GroupID: 123456789, } settings, _ := json.Marshal(vkCfg) bc := &config.Channel{ Enabled: true, Type: "vk", AllowFrom: []string{"123456789"}, Settings: settings, } ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error: %v", err) } if !ch.IsAllowedSender(bus.SenderInfo{PlatformID: "123456789"}) { t.Error("user 123456789 should be allowed") } if ch.IsAllowedSender(bus.SenderInfo{PlatformID: "999999999"}) { t.Error("user 999999999 should not be allowed") } }) t.Run("with group_trigger", func(t *testing.T) { vkCfg := config.VKSettings{ Token: *config.NewSecureString("test_token"), GroupID: 123456789, } settings, _ := json.Marshal(vkCfg) bc := &config.Channel{ Enabled: true, Type: "vk", GroupTrigger: config.GroupTriggerConfig{ MentionOnly: false, Prefixes: []string{"/bot", "!bot"}, }, Settings: settings, } ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error: %v", err) } if ch.Name() != "vk" { t.Errorf("Name() = %q, want %q", ch.Name(), "vk") } }) } func TestVKChannel_MaxMessageLength(t *testing.T) { msgBus := bus.NewMessageBus() bc := makeVKTestBaseChannel(config.VKSettings{ Token: *config.NewSecureString("test_token"), GroupID: 123456789, }) ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error: %v", err) } maxLen := ch.MaxMessageLength() if maxLen != 4000 { t.Errorf("MaxMessageLength() = %d, want 4000", maxLen) } } func TestVKChannel_SplitMessage(t *testing.T) { tests := []struct { name string content string maxLen int want int }{ { name: "short message", content: "hello", maxLen: 4000, want: 1, }, { name: "exact length", content: string(make([]byte, 4000)), maxLen: 4000, want: 1, }, { name: "needs split", content: string(make([]byte, 5000)), maxLen: 4000, want: 2, }, { name: "empty message", content: "", maxLen: 4000, want: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := channels.SplitMessage(tt.content, tt.maxLen) if len(got) != tt.want { t.Errorf("SplitMessage() got %d parts, want %d parts", len(got), tt.want) } }) } } func TestVKChannel_ProcessAttachments(t *testing.T) { tests := []struct { name string attachments []string want string }{ { name: "empty attachments", attachments: []string{}, want: "", }, { name: "photo attachment", attachments: []string{"photo"}, want: "[photo]", }, { name: "video attachment", attachments: []string{"video"}, want: "[video]", }, { name: "audio attachment", attachments: []string{"audio"}, want: "[audio]", }, { name: "document attachment", attachments: []string{"doc"}, want: "[doc]", }, { name: "sticker attachment", attachments: []string{"sticker"}, want: "[sticker]", }, { name: "audio_message attachment", attachments: []string{"audio_message"}, want: "[voice]", }, { name: "multiple attachments", attachments: []string{"photo", "video", "audio"}, want: "[photo] [video] [audio]", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var result string for i, att := range tt.attachments { if i > 0 { result += " " } if att == "audio_message" { result += "[voice]" } else { result += "[" + att + "]" } } if result != tt.want { t.Errorf("processAttachments() = %q, want %q", result, tt.want) } }) } } func TestVKChannel_VoiceCapabilities(t *testing.T) { msgBus := bus.NewMessageBus() bc := makeVKTestBaseChannel(config.VKSettings{ Token: *config.NewSecureString("test_token"), GroupID: 123456789, }) ch, err := NewVKChannel("vk", bc, msgBus) if err != nil { t.Fatalf("unexpected error: %v", err) } caps := ch.VoiceCapabilities() if !caps.ASR { t.Error("VoiceCapabilities().ASR should be true") } if !caps.TTS { t.Error("VoiceCapabilities().TTS should be true") } }