234 lines
7.6 KiB
Go
234 lines
7.6 KiB
Go
package rpc
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"testing"
|
||
|
||
"github.com/iamxvbaba/td/tg"
|
||
"github.com/iamxvbaba/td/tgerr"
|
||
)
|
||
|
||
func TestSendMediaPrivateGeoPoint(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
point := &tg.InputGeoPoint{Lat: 39.9042, Long: 116.4074}
|
||
point.SetAccuracyRadius(30) // gotd flag 字段必须 Set*() 置 flag 位,直接赋字段 getter 读不到
|
||
updates, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaGeoPoint{GeoPoint: point},
|
||
RandomID: 2001,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMedia geo: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
media, ok := msg.Media.(*tg.MessageMediaGeo)
|
||
if !ok {
|
||
t.Fatalf("expected MessageMediaGeo, got %T", msg.Media)
|
||
}
|
||
geo, ok := media.Geo.(*tg.GeoPoint)
|
||
if !ok {
|
||
t.Fatalf("expected tg.GeoPoint, got %T", media.Geo)
|
||
}
|
||
if geo.Lat != 39.9042 || geo.Long != 116.4074 {
|
||
t.Errorf("geo = (%v, %v), want (39.9042, 116.4074)", geo.Lat, geo.Long)
|
||
}
|
||
if geo.AccessHash == 0 {
|
||
t.Error("geo access_hash should be non-zero (clients echo it to upload.getWebFile)")
|
||
}
|
||
if radius, ok := geo.GetAccuracyRadius(); !ok || radius != 30 {
|
||
t.Errorf("accuracy_radius = %d (%v), want 30", radius, ok)
|
||
}
|
||
}
|
||
|
||
func TestSendMediaGeoPointOutOfRange(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
for _, point := range []*tg.InputGeoPoint{
|
||
{Lat: 90.5, Long: 0},
|
||
{Lat: -91, Long: 0},
|
||
{Lat: 0, Long: 180.01},
|
||
{Lat: 0, Long: -181},
|
||
} {
|
||
_, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaGeoPoint{GeoPoint: point},
|
||
RandomID: 2002,
|
||
})
|
||
if err == nil || !tgerr.Is(err, "MEDIA_INVALID") {
|
||
t.Errorf("geo (%v,%v): err = %v, want MEDIA_INVALID", point.Lat, point.Long, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestSendMediaGeoPointEmpty(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
_, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaGeoPoint{GeoPoint: &tg.InputGeoPointEmpty{}},
|
||
RandomID: 2003,
|
||
})
|
||
if err == nil || !tgerr.Is(err, "MEDIA_EMPTY") {
|
||
t.Fatalf("err = %v, want MEDIA_EMPTY", err)
|
||
}
|
||
}
|
||
|
||
func TestSendMediaPrivateVenue(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
updates, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaVenue{
|
||
GeoPoint: &tg.InputGeoPoint{Lat: 31.2304, Long: 121.4737},
|
||
Title: "People's Square",
|
||
Address: "Huangpu, Shanghai",
|
||
Provider: "foursquare",
|
||
VenueID: "4b5b3c4ff964a520fd0029e3",
|
||
VenueType: "arts_entertainment/default",
|
||
},
|
||
RandomID: 2004,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMedia venue: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
media, ok := msg.Media.(*tg.MessageMediaVenue)
|
||
if !ok {
|
||
t.Fatalf("expected MessageMediaVenue, got %T", msg.Media)
|
||
}
|
||
if media.Title != "People's Square" || media.Address != "Huangpu, Shanghai" ||
|
||
media.Provider != "foursquare" || media.VenueID != "4b5b3c4ff964a520fd0029e3" ||
|
||
media.VenueType != "arts_entertainment/default" {
|
||
t.Fatalf("venue media = %+v, want preserved venue payload", media)
|
||
}
|
||
geo, ok := media.Geo.(*tg.GeoPoint)
|
||
if !ok || geo.Lat != 31.2304 || geo.Long != 121.4737 {
|
||
t.Fatalf("venue geo = %#v, want (31.2304, 121.4737)", media.Geo)
|
||
}
|
||
}
|
||
|
||
func TestSendMediaVenueWithoutTitle(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
_, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaVenue{
|
||
GeoPoint: &tg.InputGeoPoint{Lat: 1, Long: 1},
|
||
Title: " ",
|
||
},
|
||
RandomID: 2005,
|
||
})
|
||
if err == nil || !tgerr.Is(err, "MEDIA_EMPTY") {
|
||
t.Fatalf("err = %v, want MEDIA_EMPTY", err)
|
||
}
|
||
}
|
||
|
||
func TestSendMediaPrivateDiceValueRanges(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
cases := []struct {
|
||
emoticon string
|
||
want string
|
||
max int
|
||
}{
|
||
{"\U0001F3B2", "\U0001F3B2", 6}, // 🎲
|
||
{"\U0001F3AF", "\U0001F3AF", 6}, // 🎯
|
||
{"\U0001F3B3", "\U0001F3B3", 6}, // 🎳
|
||
{"\U0001F3C0", "\U0001F3C0", 5}, // 🏀
|
||
{"⚽", "⚽", 5}, // 裸足球
|
||
{"⚽️", "⚽", 5}, // 带 U+FE0F 变体,须归一
|
||
{"\U0001F3B0", "\U0001F3B0", 64}, // 🎰
|
||
}
|
||
randomID := int64(3000)
|
||
for _, tc := range cases {
|
||
// 多抽几次覆盖取值边界;value 必须始终落在 [1, max]。
|
||
for i := 0; i < 8; i++ {
|
||
randomID++
|
||
updates, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaDice{Emoticon: tc.emoticon},
|
||
RandomID: randomID,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMedia dice %q: %v", tc.emoticon, err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
media, ok := msg.Media.(*tg.MessageMediaDice)
|
||
if !ok {
|
||
t.Fatalf("expected MessageMediaDice, got %T", msg.Media)
|
||
}
|
||
if media.Emoticon != tc.want {
|
||
t.Fatalf("dice emoticon = %q, want %q", media.Emoticon, tc.want)
|
||
}
|
||
if media.Value < 1 || media.Value > tc.max {
|
||
t.Fatalf("dice %q value = %d, want in [1, %d]", tc.emoticon, media.Value, tc.max)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestSendMediaDiceUnknownEmoticon(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
|
||
_, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaDice{Emoticon: "\U0001F600"},
|
||
RandomID: 3100,
|
||
})
|
||
if err == nil || !tgerr.Is(err, "EMOTICON_INVALID") {
|
||
t.Fatalf("err = %v, want EMOTICON_INVALID", err)
|
||
}
|
||
}
|
||
|
||
func TestUploadGetWebFileGeoTile(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, _ := newMediaTestRouter(t)
|
||
|
||
req := &tg.UploadGetWebFileRequest{
|
||
Location: &tg.InputWebFileGeoPointLocation{
|
||
GeoPoint: &tg.InputGeoPoint{Lat: 39.9, Long: 116.4},
|
||
AccessHash: 12345,
|
||
W: 100, H: 100, Zoom: 15, Scale: 1,
|
||
},
|
||
Offset: 0,
|
||
Limit: 1 << 17,
|
||
}
|
||
file, err := r.onUploadGetWebFile(WithUserID(ctx, owner.ID), req)
|
||
if err != nil {
|
||
t.Fatalf("getWebFile: %v", err)
|
||
}
|
||
if file.Size != 12 || len(file.Bytes) != 12 {
|
||
t.Fatalf("size = %d bytes = %d, want 12/12 (fake tile)", file.Size, len(file.Bytes))
|
||
}
|
||
if file.MimeType != "image/png" {
|
||
t.Errorf("mime = %q, want image/png", file.MimeType)
|
||
}
|
||
|
||
// offset 续传按字节切片,size 始终是全量大小。
|
||
req.Offset = 4
|
||
req.Limit = 4
|
||
chunk, err := r.onUploadGetWebFile(WithUserID(ctx, owner.ID), req)
|
||
if err != nil {
|
||
t.Fatalf("getWebFile offset: %v", err)
|
||
}
|
||
if chunk.Size != 12 || !bytes.Equal(chunk.Bytes, []byte{0x0D, 0x0A, 0x1A, 0x0A}) {
|
||
t.Fatalf("offset chunk = %v (size %d), want bytes 4..8 of tile", chunk.Bytes, chunk.Size)
|
||
}
|
||
|
||
// URL 形态当前无来源,必须显式拒绝而非静默。
|
||
if _, err := r.onUploadGetWebFile(WithUserID(ctx, owner.ID), &tg.UploadGetWebFileRequest{
|
||
Location: &tg.InputWebFileLocation{URL: "https://example.com/a.png", AccessHash: 1},
|
||
Limit: 4096,
|
||
}); err == nil || !tgerr.Is(err, "LOCATION_INVALID") {
|
||
t.Fatalf("url webfile err = %v, want LOCATION_INVALID", err)
|
||
}
|
||
}
|