package kook import ( "context" "net/http" "sync" "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter" ) func TestSendMessage_GroupText(t *testing.T) { t.Parallel() var mu sync.Mutex var body map[string]any var auth string h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != channelMessagePath { http.Error(w, "unexpected path: "+r.URL.Path, http.StatusNotFound) return } mu.Lock() auth = r.Header.Get("Authorization") body = decodeBody(r) mu.Unlock() kookOK(w, map[string]any{"msg_id": "x-1", "msg_timestamp": 1}) }) a, _ := newTestAdapter(t, h) a.connected = true resp := adapter.UnifiedResponse{ ReplyTo: "reply-99", Messages: []adapter.UnifiedMessage{ {ChannelID: "chan-1", ChannelType: adapter.ChannelGroup, Content: "hello", ContentType: adapter.ContentText}, }, } if err := a.SendMessage(context.Background(), resp); err != nil { t.Fatalf("SendMessage: %v", err) } mu.Lock() defer mu.Unlock() if auth != "Bot testtoken" { t.Errorf("Authorization = %q, want Bot testtoken", auth) } if body["target_id"] != "chan-1" { t.Errorf("target_id = %v, want chan-1", body["target_id"]) } if body["type"] != float64(9) { t.Errorf("type = %v, want 9 (kmarkdown)", body["type"]) } if body["content"] != "hello" { t.Errorf("content = %v, want hello", body["content"]) } if body["quote"] != "reply-99" { t.Errorf("quote = %v, want reply-99", body["quote"]) } } func TestSendMessage_PrivateText(t *testing.T) { t.Parallel() var mu sync.Mutex var body map[string]any h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != privateMessagePath { http.Error(w, "unexpected path: "+r.URL.Path, http.StatusNotFound) return } mu.Lock() body = decodeBody(r) mu.Unlock() kookOK(w, map[string]any{"msg_id": "x-2", "msg_timestamp": 1}) }) a, _ := newTestAdapter(t, h) a.connected = true resp := adapter.UnifiedResponse{ Messages: []adapter.UnifiedMessage{ {ChannelID: "user-9", ChannelType: adapter.ChannelDirect, Content: "private hi", ContentType: adapter.ContentText}, }, } if err := a.SendMessage(context.Background(), resp); err != nil { t.Fatalf("SendMessage: %v", err) } mu.Lock() defer mu.Unlock() if body["target_id"] != "user-9" || body["content"] != "private hi" { t.Errorf("body = %v, want target_id user-9 content private hi", body) } } func TestSendMessage_MediaTypeMapping(t *testing.T) { t.Parallel() for _, tc := range []struct { name string ct adapter.ContentType media adapter.Media wantType int }{ {name: "image", ct: adapter.ContentImage, media: adapter.Media{Kind: adapter.MediaImage, URL: "https://img/a.jpg"}, wantType: 2}, {name: "voice", ct: adapter.ContentVoice, media: adapter.Media{Kind: adapter.MediaVoice, URL: "https://img/a.mp3"}, wantType: 8}, {name: "video", ct: adapter.ContentFile, media: adapter.Media{Kind: adapter.MediaVideo, URL: "https://img/a.mp4"}, wantType: 3}, {name: "file", ct: adapter.ContentFile, media: adapter.Media{Kind: adapter.MediaFile, URL: "https://img/a.txt"}, wantType: 4}, } { t.Run(tc.name, func(t *testing.T) { t.Parallel() var mu sync.Mutex var body map[string]any h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != channelMessagePath { http.Error(w, "unexpected path", http.StatusNotFound) return } mu.Lock() body = decodeBody(r) mu.Unlock() kookOK(w, map[string]any{"msg_id": "x", "msg_timestamp": 1}) }) a, _ := newTestAdapter(t, h) a.connected = true resp := adapter.UnifiedResponse{ Messages: []adapter.UnifiedMessage{ {ChannelID: "chan-1", ChannelType: adapter.ChannelGroup, ContentType: tc.ct, Media: []adapter.Media{tc.media}}, }, } if err := a.SendMessage(context.Background(), resp); err != nil { t.Fatalf("SendMessage: %v", err) } mu.Lock() defer mu.Unlock() if body["type"] != float64(tc.wantType) { t.Errorf("type = %v, want %d", body["type"], tc.wantType) } if body["content"] != tc.media.URL { t.Errorf("content = %v, want %s", body["content"], tc.media.URL) } }) } } func TestSendProactive_Private(t *testing.T) { t.Parallel() var mu sync.Mutex var body map[string]any h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != privateMessagePath { http.Error(w, "unexpected path", http.StatusNotFound) return } mu.Lock() body = decodeBody(r) mu.Unlock() kookOK(w, map[string]any{"msg_id": "x-3", "msg_timestamp": 1}) }) a, _ := newTestAdapter(t, h) a.connected = true if err := a.SendProactive(context.Background(), adapter.UnifiedMessage{ ChannelID: "user-9", ChannelType: adapter.ChannelDirect, Content: "reminder", ContentType: adapter.ContentText, }); err != nil { t.Fatalf("SendProactive: %v", err) } mu.Lock() defer mu.Unlock() if body["target_id"] != "user-9" || body["content"] != "reminder" { t.Errorf("body = %v, want target_id user-9 content reminder", body) } } func TestSendMessage_NoTarget(t *testing.T) { t.Parallel() a, _ := newTestAdapter(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "unexpected", http.StatusNotFound) })) a.connected = true err := a.SendMessage(context.Background(), adapter.UnifiedResponse{ Messages: []adapter.UnifiedMessage{{ContentType: adapter.ContentText, Content: "hi"}}, }) if err == nil { t.Fatal("expected error for missing target") } }