200 lines
6.3 KiB
Go
200 lines
6.3 KiB
Go
package rpc
|
||
|
||
import (
|
||
"encoding/json"
|
||
"testing"
|
||
|
||
"github.com/gotd/td/bin"
|
||
"github.com/gotd/td/tg"
|
||
|
||
"telesrv/internal/domain"
|
||
)
|
||
|
||
// jsonRoundTripMedia 复刻 postgres 媒体 codec(json.Marshal/Unmarshal)以验证
|
||
// 新增的 web_page 字段经 JSONB 列字节级 round-trip 后 Kind 与载荷不丢失。
|
||
func jsonRoundTripMedia(t *testing.T, m *domain.MessageMedia) *domain.MessageMedia {
|
||
t.Helper()
|
||
raw, err := json.Marshal(m)
|
||
if err != nil {
|
||
t.Fatalf("marshal media: %v", err)
|
||
}
|
||
var out domain.MessageMedia
|
||
if err := json.Unmarshal(raw, &out); err != nil {
|
||
t.Fatalf("unmarshal media: %v", err)
|
||
}
|
||
if out.IsZero() {
|
||
t.Fatalf("web_page media decoded as zero (Kind lost): %s", raw)
|
||
}
|
||
return &out
|
||
}
|
||
|
||
// TestTgMessageMediaWebPageDone 验证 done 形态投影为 messageMediaWebPage{webPage},
|
||
// 字段齐全且能二进制编码(捕获非可选 id/url/display_url/hash 缺失)。
|
||
func TestTgMessageMediaWebPageDone(t *testing.T) {
|
||
src := &domain.MessageMedia{
|
||
Kind: domain.MessageMediaKindWebPage,
|
||
WebPage: &domain.MessageWebPage{
|
||
State: domain.MessageWebPageStateDone,
|
||
ID: 0x1234abcd,
|
||
URL: "https://example.com/article",
|
||
DisplayURL: "example.com",
|
||
Hash: 42,
|
||
Type: "article",
|
||
SiteName: "Example",
|
||
Title: "An Example Article",
|
||
Description: "A description of the article.",
|
||
Author: "Jane Doe",
|
||
ForceLargeMedia: true,
|
||
HasLargeMedia: true,
|
||
Photo: &domain.Photo{
|
||
ID: 0x99,
|
||
AccessHash: 0x55,
|
||
DCID: 2,
|
||
Sizes: []domain.PhotoSize{
|
||
{Kind: domain.PhotoSizeKindDefault, Type: "x", W: 1280, H: 720, Size: 4096},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
got := tgMessageMedia(jsonRoundTripMedia(t, src))
|
||
wrap, ok := got.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("tgMessageMedia = %T, want *tg.MessageMediaWebPage", got)
|
||
}
|
||
if !wrap.ForceLargeMedia {
|
||
t.Errorf("ForceLargeMedia = false, want true")
|
||
}
|
||
page, ok := wrap.Webpage.(*tg.WebPage)
|
||
if !ok {
|
||
t.Fatalf("Webpage = %T, want *tg.WebPage", wrap.Webpage)
|
||
}
|
||
if page.ID != src.WebPage.ID || page.URL != src.WebPage.URL || page.DisplayURL != src.WebPage.DisplayURL || page.Hash != src.WebPage.Hash {
|
||
t.Errorf("non-optional fields mismatch: %+v", page)
|
||
}
|
||
if !page.HasLargeMedia {
|
||
t.Errorf("HasLargeMedia = false, want true")
|
||
}
|
||
if v, ok := page.GetSiteName(); !ok || v != "Example" {
|
||
t.Errorf("SiteName = %q (ok=%v), want Example", v, ok)
|
||
}
|
||
if v, ok := page.GetTitle(); !ok || v != "An Example Article" {
|
||
t.Errorf("Title = %q (ok=%v)", v, ok)
|
||
}
|
||
if v, ok := page.GetAuthor(); !ok || v != "Jane Doe" {
|
||
t.Errorf("Author = %q (ok=%v)", v, ok)
|
||
}
|
||
if photo, ok := page.GetPhoto(); !ok {
|
||
t.Errorf("GetPhoto ok=false, want embedded photo")
|
||
} else if _, isReal := photo.(*tg.Photo); !isReal {
|
||
t.Errorf("GetPhoto = %T, want *tg.Photo", photo)
|
||
}
|
||
|
||
// 二进制编码确认非可选字段齐全(messageMediaWebPage.EncodeBare 会在 webpage
|
||
// 为 nil 或缺非可选字段时报错)。
|
||
var buf bin.Buffer
|
||
if err := wrap.Encode(&buf); err != nil {
|
||
t.Fatalf("encode messageMediaWebPage: %v", err)
|
||
}
|
||
}
|
||
|
||
func TestTgMessageMediaWebPageAiComposeToneAttribute(t *testing.T) {
|
||
src := &domain.MessageMedia{
|
||
Kind: domain.MessageMediaKindWebPage,
|
||
WebPage: &domain.MessageWebPage{
|
||
State: domain.MessageWebPageStateDone,
|
||
ID: 123,
|
||
URL: "https://t.me/addstyle/ai-test",
|
||
DisplayURL: "t.me/addstyle/ai-test",
|
||
Hash: 7,
|
||
Type: "telegram_aicomposetone",
|
||
Title: "Sharp",
|
||
ComposeToneEmojiID: 99,
|
||
},
|
||
}
|
||
got := tgMessageMedia(jsonRoundTripMedia(t, src))
|
||
wrap, ok := got.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("tgMessageMedia = %T, want *tg.MessageMediaWebPage", got)
|
||
}
|
||
page, ok := wrap.Webpage.(*tg.WebPage)
|
||
if !ok {
|
||
t.Fatalf("Webpage = %T, want *tg.WebPage", wrap.Webpage)
|
||
}
|
||
attrs, ok := page.GetAttributes()
|
||
if !ok || len(attrs) != 1 {
|
||
t.Fatalf("attributes = %#v ok=%v, want one", attrs, ok)
|
||
}
|
||
attr, ok := attrs[0].(*tg.WebPageAttributeAiComposeTone)
|
||
if !ok || attr.EmojiID != 99 {
|
||
t.Fatalf("attribute = %#v, want AiComposeTone emoji 99", attrs[0])
|
||
}
|
||
}
|
||
|
||
// TestTgMessageMediaWebPagePending 验证 pending 形态投影为 webPagePending{id,url,date}。
|
||
func TestTgMessageMediaWebPagePending(t *testing.T) {
|
||
src := &domain.MessageMedia{
|
||
Kind: domain.MessageMediaKindWebPage,
|
||
WebPage: &domain.MessageWebPage{
|
||
State: domain.MessageWebPageStatePending,
|
||
ID: 777,
|
||
URL: "https://pending.example/x",
|
||
Date: 1700000000,
|
||
},
|
||
}
|
||
got := tgMessageMedia(jsonRoundTripMedia(t, src))
|
||
wrap, ok := got.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("tgMessageMedia = %T, want *tg.MessageMediaWebPage", got)
|
||
}
|
||
pending, ok := wrap.Webpage.(*tg.WebPagePending)
|
||
if !ok {
|
||
t.Fatalf("Webpage = %T, want *tg.WebPagePending", wrap.Webpage)
|
||
}
|
||
if pending.ID != 777 || pending.Date != 1700000000 {
|
||
t.Errorf("pending = %+v, want id=777 date=1700000000", pending)
|
||
}
|
||
if v, ok := pending.GetURL(); !ok || v != src.WebPage.URL {
|
||
t.Errorf("pending URL = %q (ok=%v)", v, ok)
|
||
}
|
||
var buf bin.Buffer
|
||
if err := wrap.Encode(&buf); err != nil {
|
||
t.Fatalf("encode pending: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestTgMessageMediaWebPageEmpty 验证 empty 形态投影为 webPageEmpty{id}。
|
||
func TestTgMessageMediaWebPageEmpty(t *testing.T) {
|
||
src := &domain.MessageMedia{
|
||
Kind: domain.MessageMediaKindWebPage,
|
||
WebPage: &domain.MessageWebPage{
|
||
State: domain.MessageWebPageStateEmpty,
|
||
ID: 555,
|
||
URL: "https://empty.example/y",
|
||
},
|
||
}
|
||
got := tgMessageMedia(jsonRoundTripMedia(t, src))
|
||
wrap, ok := got.(*tg.MessageMediaWebPage)
|
||
if !ok {
|
||
t.Fatalf("tgMessageMedia = %T, want *tg.MessageMediaWebPage", got)
|
||
}
|
||
empty, ok := wrap.Webpage.(*tg.WebPageEmpty)
|
||
if !ok {
|
||
t.Fatalf("Webpage = %T, want *tg.WebPageEmpty", wrap.Webpage)
|
||
}
|
||
if empty.ID != 555 {
|
||
t.Errorf("empty.ID = %d, want 555", empty.ID)
|
||
}
|
||
var buf bin.Buffer
|
||
if err := wrap.Encode(&buf); err != nil {
|
||
t.Fatalf("encode empty: %v", err)
|
||
}
|
||
}
|
||
|
||
// TestTgMessageMediaWebPageNilGuards 验证 nil WebPage 不会 panic 且回退空媒体。
|
||
func TestTgMessageMediaWebPageNilGuards(t *testing.T) {
|
||
got := tgMessageMedia(&domain.MessageMedia{Kind: domain.MessageMediaKindWebPage})
|
||
if _, ok := got.(*tg.MessageMediaEmpty); !ok {
|
||
t.Fatalf("nil WebPage = %T, want *tg.MessageMediaEmpty", got)
|
||
}
|
||
}
|