203 lines
7.1 KiB
Go
203 lines
7.1 KiB
Go
package rpc
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
|
||
"github.com/iamxvbaba/td/tg"
|
||
|
||
"telesrv/internal/domain"
|
||
)
|
||
|
||
// "see https://example.com/x" 的 URL 在 UTF-16 偏移 4、长度 21。
|
||
const (
|
||
wpTestMessage = "see https://example.com/x"
|
||
wpTestURL = "https://example.com/x"
|
||
wpURLEntityOff = 4
|
||
wpURLEntityLen = 21
|
||
)
|
||
|
||
func wpURLEntities() []tg.MessageEntityClass {
|
||
return []tg.MessageEntityClass{&tg.MessageEntityURL{Offset: wpURLEntityOff, Length: wpURLEntityLen}}
|
||
}
|
||
|
||
// TestSendMessageAttachesWebPagePending 验证启用预览时,带 URL 的文本消息挂上 pending 占位
|
||
// (id==url_hash 保证与 done 解析关联),并投影 invert_media。
|
||
func TestSendMessageAttachesWebPagePending(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Message: wpTestMessage,
|
||
Entities: wpURLEntities(),
|
||
RandomID: 5101,
|
||
InvertMedia: true,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
|
||
wrap, ok := msg.Media.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("media = %T, want *tg.MessageMediaWebPage", msg.Media)
|
||
}
|
||
pending, ok := wrap.Webpage.(*tg.WebPagePending)
|
||
if !ok {
|
||
t.Fatalf("webpage = %T, want *tg.WebPagePending", wrap.Webpage)
|
||
}
|
||
wantID := domain.WebPageURLHash(wpTestURL)
|
||
if pending.ID != wantID {
|
||
t.Errorf("pending id = %d, want url_hash %d", pending.ID, wantID)
|
||
}
|
||
if url, _ := pending.GetURL(); url != wpTestURL {
|
||
t.Errorf("pending url = %q, want %q", url, wpTestURL)
|
||
}
|
||
if !msg.InvertMedia {
|
||
t.Errorf("invert_media not projected onto message")
|
||
}
|
||
}
|
||
|
||
// TestSendMessageAttachesCachedDoneCard 验证:URL 已缓存解析时,发送 echo 直接带 done 卡片
|
||
// (非 pending)——官方行为,TDesktop 据此立即渲染、不依赖异步换卡。
|
||
func TestSendMessageAttachesCachedDoneCard(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
f := r.deps.Files.(*fakeFiles)
|
||
f.webPagePreviewOn = true
|
||
f.lookupWebPageFn = func(u string) (domain.MessageWebPage, bool) {
|
||
return domain.MessageWebPage{State: domain.MessageWebPageStateDone, ID: domain.WebPageURLHash(u), URL: u, DisplayURL: "example.com", Title: "Cached"}, true
|
||
}
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash}, Message: wpTestMessage, Entities: wpURLEntities(), RandomID: 5201,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
wrap, ok := msg.Media.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("media = %T, want *tg.MessageMediaWebPage", msg.Media)
|
||
}
|
||
page, ok := wrap.Webpage.(*tg.WebPage)
|
||
if !ok {
|
||
t.Fatalf("echo webpage = %T, want *tg.WebPage (done card directly)", wrap.Webpage)
|
||
}
|
||
if v, _ := page.GetTitle(); v != "Cached" {
|
||
t.Errorf("title = %q, want Cached", v)
|
||
}
|
||
}
|
||
|
||
// TestSendMessageNoWebpageSuppressesPreview 验证 no_webpage 抑制占位。
|
||
func TestSendMessageNoWebpageSuppressesPreview(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Message: wpTestMessage,
|
||
Entities: wpURLEntities(),
|
||
RandomID: 5102,
|
||
NoWebpage: true,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
if msg := newMessageFromUpdates(t, updates); msg.Media != nil {
|
||
t.Fatalf("media = %T, want nil (no_webpage)", msg.Media)
|
||
}
|
||
}
|
||
|
||
// TestSendMessagePreviewDisabledNoPlaceholder 验证未启用预览时不挂占位(否则永久 pending)。
|
||
func TestSendMessagePreviewDisabledNoPlaceholder(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
// webPagePreviewOn 默认 false。
|
||
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Message: wpTestMessage,
|
||
Entities: wpURLEntities(),
|
||
RandomID: 5103,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
if msg := newMessageFromUpdates(t, updates); msg.Media != nil {
|
||
t.Fatalf("media = %T, want nil (preview disabled)", msg.Media)
|
||
}
|
||
}
|
||
|
||
// TestSendMediaInputWebPageAttachesPending 验证 sendMedia 的 InputMediaWebPage 经降级到
|
||
// sendMessage 后,仍从文本 URL 挂上 pending 占位(启用预览时)。
|
||
func TestSendMediaInputWebPageAttachesPending(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||
|
||
updates, err := r.onMessagesSendMedia(WithUserID(ctx, owner.ID), &tg.MessagesSendMediaRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Media: &tg.InputMediaWebPage{URL: wpTestURL},
|
||
Message: wpTestMessage,
|
||
Entities: wpURLEntities(),
|
||
RandomID: 5105,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMedia webpage: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
wrap, ok := msg.Media.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("media = %T, want *tg.MessageMediaWebPage", msg.Media)
|
||
}
|
||
if _, ok := wrap.Webpage.(*tg.WebPagePending); !ok {
|
||
t.Fatalf("webpage = %T, want *tg.WebPagePending", wrap.Webpage)
|
||
}
|
||
}
|
||
|
||
// TestSendMessageHighlightsBareURL 验证服务端为不带 url 实体的消息(如 TDesktop 发的)补
|
||
// MessageEntityURL,使链接高亮——独立于预览是否启用。
|
||
func TestSendMessageHighlightsBareURL(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Message: "see https://example.com/x",
|
||
RandomID: 5301, // 无 entities,模拟 TDesktop
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
msg := newMessageFromUpdates(t, updates)
|
||
var found bool
|
||
for _, e := range msg.Entities {
|
||
if u, ok := e.(*tg.MessageEntityURL); ok && u.Offset == 4 && u.Length == 21 {
|
||
found = true
|
||
}
|
||
}
|
||
if !found {
|
||
t.Fatalf("sent message missing url highlight entity: %+v", msg.Entities)
|
||
}
|
||
}
|
||
|
||
// TestSendMessageNoURLNoPlaceholder 验证无 URL 实体时不挂占位。
|
||
func TestSendMessageNoURLNoPlaceholder(t *testing.T) {
|
||
ctx := context.Background()
|
||
r, owner, friend := newMediaTestRouter(t)
|
||
r.deps.Files.(*fakeFiles).webPagePreviewOn = true
|
||
|
||
updates, err := r.onMessagesSendMessage(WithUserID(ctx, owner.ID), &tg.MessagesSendMessageRequest{
|
||
Peer: &tg.InputPeerUser{UserID: friend.ID, AccessHash: friend.AccessHash},
|
||
Message: "just plain text, no link",
|
||
RandomID: 5104,
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("sendMessage: %v", err)
|
||
}
|
||
if msg := newMessageFromUpdates(t, updates); msg.Media != nil {
|
||
t.Fatalf("media = %T, want nil (no url)", msg.Media)
|
||
}
|
||
}
|