201 lines
5.5 KiB
Go
201 lines
5.5 KiB
Go
package weixin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestBodyFromItemList_Text(t *testing.T) {
|
|
got := bodyFromItemList([]messageItem{
|
|
{Type: messageItemText, TextItem: &textItem{Text: " hello "}},
|
|
})
|
|
if got != "hello" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBodyFromItemList_VoiceText(t *testing.T) {
|
|
got := bodyFromItemList([]messageItem{
|
|
{Type: messageItemVoice, VoiceItem: &voiceItem{Text: "transcribed"}},
|
|
})
|
|
if got != "transcribed" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBodyFromItemList_Quote(t *testing.T) {
|
|
ref := &refMessage{
|
|
Title: "t",
|
|
MessageItem: &messageItem{
|
|
Type: messageItemText,
|
|
TextItem: &textItem{Text: "inner"},
|
|
},
|
|
}
|
|
got := bodyFromItemList([]messageItem{
|
|
{Type: messageItemText, TextItem: &textItem{Text: "reply"}, RefMsg: ref},
|
|
})
|
|
want := "[引用: t | inner]\nreply"
|
|
if got != want {
|
|
t.Fatalf("got %q want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSplitUTF8(t *testing.T) {
|
|
s := string([]rune{'a', '啊', 'b', '吧', 'c'})
|
|
parts := splitUTF8(s, 2)
|
|
if len(parts) != 3 || parts[0] != "a啊" || parts[1] != "b吧" || parts[2] != "c" {
|
|
t.Fatalf("parts=%#v", parts)
|
|
}
|
|
}
|
|
|
|
func TestSplitUTF8Empty(t *testing.T) {
|
|
parts := splitUTF8("", maxWeixinChunk)
|
|
if len(parts) != 1 || parts[0] != "" {
|
|
t.Fatalf("parts=%#v", parts)
|
|
}
|
|
}
|
|
|
|
func TestMediaOnlyItems(t *testing.T) {
|
|
if !mediaOnlyItems([]messageItem{{Type: messageItemImage}}) {
|
|
t.Fatal("image should be media-only")
|
|
}
|
|
if mediaOnlyItems([]messageItem{{Type: messageItemVoice, VoiceItem: &voiceItem{Text: "x"}}}) {
|
|
t.Fatal("voice with text is not media-only")
|
|
}
|
|
}
|
|
|
|
func TestCollectInboundMediaUsesCDNHTTPClient(t *testing.T) {
|
|
png := []byte{0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'}
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/download" {
|
|
t.Fatalf("path = %q, want /download", r.URL.Path)
|
|
}
|
|
if r.URL.Query().Get("encrypted_query_param") != "image-ref" {
|
|
t.Fatalf("encrypted_query_param = %q, want image-ref", r.URL.Query().Get("encrypted_query_param"))
|
|
}
|
|
_, _ = w.Write(png)
|
|
}))
|
|
defer server.Close()
|
|
|
|
p := &Platform{
|
|
cdnBaseURL: server.URL,
|
|
httpClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
|
|
return nil, errors.New("api client should not download media")
|
|
})},
|
|
cdnHttpClient: server.Client(),
|
|
}
|
|
|
|
images, files, audio := p.collectInboundMedia(context.Background(), []messageItem{{
|
|
Type: messageItemImage,
|
|
ImageItem: &imageItem{
|
|
Media: &cdnMedia{EncryptQueryParam: "image-ref"},
|
|
},
|
|
}})
|
|
|
|
if len(images) != 1 {
|
|
t.Fatalf("images len = %d, want 1", len(images))
|
|
}
|
|
if images[0].MimeType != "image/png" {
|
|
t.Fatalf("mime = %q, want image/png", images[0].MimeType)
|
|
}
|
|
if string(images[0].Data) != string(png) {
|
|
t.Fatalf("image data = %v, want %v", images[0].Data, png)
|
|
}
|
|
if len(files) != 0 {
|
|
t.Fatalf("files len = %d, want 0", len(files))
|
|
}
|
|
if audio != nil {
|
|
t.Fatalf("audio = %#v, want nil", audio)
|
|
}
|
|
}
|
|
|
|
func TestSendMessageResp_JSON(t *testing.T) {
|
|
var r sendMessageResp
|
|
if err := json.Unmarshal([]byte(`{"ret":-1,"errcode":100,"errmsg":"rate limited"}`), &r); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r.Ret != -1 || r.Errcode != 100 || r.Errmsg != "rate limited" {
|
|
t.Fatalf("got %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestSendAudioRejectsEmptyAudio(t *testing.T) {
|
|
p := &Platform{}
|
|
// resolveReplyContext checks context_token first, so provide one
|
|
rc := &replyContext{peerUserID: "test", contextToken: "valid-token"}
|
|
err := p.SendAudio(context.Background(), rc, []byte{}, "wav")
|
|
if err == nil {
|
|
t.Fatal("expected error for empty audio")
|
|
}
|
|
if !containsStr(err.Error(), "empty audio") {
|
|
t.Fatalf("expected 'empty audio' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSendAudioRejectsInvalidReplyContext(t *testing.T) {
|
|
p := &Platform{}
|
|
err := p.SendAudio(context.Background(), "invalid-context", []byte("audio-data"), "wav")
|
|
if err == nil {
|
|
t.Fatal("expected error for invalid reply context")
|
|
}
|
|
if !containsStr(err.Error(), "invalid reply context") {
|
|
t.Fatalf("expected 'invalid reply context' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSendAudioRejectsNilReplyContext(t *testing.T) {
|
|
p := &Platform{}
|
|
err := p.SendAudio(context.Background(), nil, []byte("audio-data"), "wav")
|
|
if err == nil {
|
|
t.Fatal("expected error for nil reply context")
|
|
}
|
|
if !containsStr(err.Error(), "invalid reply context") {
|
|
t.Fatalf("expected 'invalid reply context' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetConfig_RejectsNonZeroErrcode(t *testing.T) {
|
|
raw := `{"ret":0,"errcode":40001,"errmsg":"invalid token","typing_ticket":""}`
|
|
var out getConfigResp
|
|
if err := json.Unmarshal([]byte(raw), &out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.Errcode != 40001 {
|
|
t.Fatalf("expected errcode 40001, got %d", out.Errcode)
|
|
}
|
|
}
|
|
|
|
func TestGetConfig_RejectsNonZeroRet(t *testing.T) {
|
|
raw := `{"ret":-1,"errcode":0,"errmsg":"internal error","typing_ticket":"tk"}`
|
|
var out getConfigResp
|
|
if err := json.Unmarshal([]byte(raw), &out); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.Ret != -1 {
|
|
t.Fatalf("expected ret -1, got %d", out.Ret)
|
|
}
|
|
}
|
|
|
|
func containsStr(s, substr string) bool {
|
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStrHelper(s, substr))
|
|
}
|
|
|
|
func containsStrHelper(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type roundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
|
return f(r)
|
|
}
|