test(message): cover pico and weixin media text semantics

This commit is contained in:
Anton Bogdanovich
2026-05-11 16:32:24 -07:00
parent 987f117f31
commit c05e5e29c6
2 changed files with 128 additions and 0 deletions
+69
View File
@@ -835,6 +835,75 @@ func TestSendMedia_DismissesTrackedToolFeedbackMessage(t *testing.T) {
}
}
func TestSendMedia_IncludesCaptionAndAttachmentsInSinglePayload(t *testing.T) {
ch := newTestPicoChannel(t)
store := media.NewFileMediaStore()
ch.SetMediaStore(store)
if err := ch.Start(context.Background()); err != nil {
t.Fatalf("Start() error = %v", err)
}
defer ch.Stop(context.Background())
clientConn, received, cleanup := newTestPicoWebSocket(t)
defer cleanup()
ch.addConnForTest(&picoConn{id: "conn-1", conn: clientConn, sessionID: "sess-1"})
localPath := filepath.Join(t.TempDir(), "photo.png")
if err := os.WriteFile(localPath, []byte("png-body"), 0o600); err != nil {
t.Fatalf("WriteFile() error = %v", err)
}
ref, err := store.Store(localPath, media.MediaMeta{
Filename: "photo.png",
ContentType: "image/png",
}, "test-scope")
if err != nil {
t.Fatalf("Store() error = %v", err)
}
_, err = ch.SendMedia(context.Background(), bus.OutboundMediaMessage{
ChatID: "pico:sess-1",
Parts: []bus.MediaPart{{
Ref: ref,
Type: "image",
Filename: "photo.png",
ContentType: "image/png",
Caption: "recipe translation",
}},
})
if err != nil {
t.Fatalf("SendMedia() error = %v", err)
}
select {
case msg := <-received:
if msg.Type != TypeMessageCreate {
t.Fatalf("message type = %q, want %q", msg.Type, TypeMessageCreate)
}
payload := msg.Payload
if got := payload[PayloadKeyContent]; got != "recipe translation" {
t.Fatalf("content = %#v, want %q", got, "recipe translation")
}
rawAttachments, ok := payload["attachments"].([]any)
if !ok || len(rawAttachments) != 1 {
t.Fatalf("attachments = %#v, want 1 attachment", payload["attachments"])
}
attachment, ok := rawAttachments[0].(map[string]any)
if !ok {
t.Fatalf("attachment = %#v, want map", rawAttachments[0])
}
if got := attachment["type"]; got != "image" {
t.Fatalf("attachment type = %#v, want image", got)
}
if got := attachment["filename"]; got != "photo.png" {
t.Fatalf("attachment filename = %#v, want photo.png", got)
}
case <-time.After(time.Second):
t.Fatal("expected media payload to be delivered")
}
}
func TestPicoDownloadURLForRef(t *testing.T) {
got, err := picoDownloadURLForRef("media://attachment-1")
if err != nil {
+59
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"io"
"net/http"
@@ -319,3 +320,61 @@ func TestSelectInboundMediaItemFallsBackToRefMessage(t *testing.T) {
t.Fatalf("selectInboundMediaItem().Type = %d, want %d", item.Type, MessageItemTypeImage)
}
}
func TestSendUploadedMedia_SendsCaptionAsSeparateTextBeforeMedia(t *testing.T) {
var requests []SendMessageReq
ch := &WeixinChannel{
api: &ApiClient{
BaseURL: "https://ilinkai.weixin.qq.com/",
HttpClient: &http.Client{Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
if r.URL.Path != "/ilink/bot/sendmessage" {
t.Fatalf("sendmessage path = %q, want /ilink/bot/sendmessage", r.URL.Path)
}
var req SendMessageReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
t.Fatalf("decode sendmessage req: %v", err)
}
requests = append(requests, req)
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader([]byte(`{"ret":0,"errcode":0}`))),
Header: make(http.Header),
}, nil
})},
},
typingCache: make(map[string]typingTicketCacheEntry),
}
err := ch.sendUploadedMedia(
context.Background(),
"user-1",
"ctx-1",
"recipe translation",
UploadMediaTypeImage,
&uploadedFileInfo{
downloadParam: "download-token",
aesKeyHex: "31323334353637383930616263646566",
fileSize: 11,
cipherSize: 16,
filename: "photo.png",
},
)
if err != nil {
t.Fatalf("sendUploadedMedia() error = %v", err)
}
if len(requests) != 2 {
t.Fatalf("sendUploadedMedia() sent %d requests, want 2", len(requests))
}
if len(requests[0].Msg.ItemList) != 1 || requests[0].Msg.ItemList[0].Type != MessageItemTypeText {
t.Fatalf("first request item = %+v, want text item", requests[0].Msg.ItemList)
}
if got := requests[0].Msg.ItemList[0].TextItem.Text; got != "recipe translation" {
t.Fatalf("first request text = %q, want recipe translation", got)
}
if len(requests[1].Msg.ItemList) != 1 || requests[1].Msg.ItemList[0].Type != MessageItemTypeImage {
t.Fatalf("second request item = %+v, want image item", requests[1].Msg.ItemList)
}
if requests[1].Msg.ItemList[0].ImageItem == nil || requests[1].Msg.ItemList[0].ImageItem.Media == nil {
t.Fatalf("second request image media = %+v, want media ref", requests[1].Msg.ItemList[0].ImageItem)
}
}