FILE / ScuroNeko/Laniakea
tgapi/api101_test.go
Исходный файл и его история в репозитории.
Golang lint / lint (push) Failing after 1m37s
(fix): finalize v2 contracts (tests): cover v2 migration (doc): prepare release guidance
359 lines
14 KiB
Go
359 lines
14 KiB
Go
package tgapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestEditMessageTextMarshalsInputRichMessage(t *testing.T) {
|
|
params := EditMessageText{
|
|
ChatID: 1,
|
|
MessageID: 2,
|
|
RichMessage: &InputRichMessage{
|
|
HTML: "<p>hi</p>",
|
|
SkipEntityDetection: true,
|
|
},
|
|
}
|
|
data, err := json.Marshal(params)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
got := string(data)
|
|
for _, want := range []string{`"rich_message":{"html":`, `"skip_entity_detection":true`} {
|
|
if !strings.Contains(got, want) {
|
|
t.Fatalf("missing %s in editMessageText JSON: %s", want, got)
|
|
}
|
|
}
|
|
if strings.Contains(got, `"blocks"`) {
|
|
t.Fatalf("rich_message must be an InputRichMessage, not a block tree: %s", got)
|
|
}
|
|
if strings.Contains(got, `"text"`) {
|
|
t.Fatalf("empty text must be omitted when editing rich content: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestSendRichMessageDraftMarshal(t *testing.T) {
|
|
params := SendRichMessageDraft{
|
|
ChatID: 1,
|
|
DraftID: 7,
|
|
RichMessage: InputRichMessage{Markdown: "*hi*"},
|
|
CanStop: true,
|
|
KeepOnStop: true,
|
|
}
|
|
data, err := json.Marshal(params)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
got := string(data)
|
|
for _, want := range []string{`"chat_id":1`, `"draft_id":7`, `"rich_message":{"markdown":"*hi*"}`, `"can_stop":true`, `"keep_on_stop":true`} {
|
|
if !strings.Contains(got, want) {
|
|
t.Fatalf("missing %s in sendRichMessageDraft JSON: %s", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInputRichMessageContentMarshal(t *testing.T) {
|
|
content := InputRichMessageContent{
|
|
RichMessage: InputRichMessage{HTML: "<p>hi</p>"},
|
|
}
|
|
data, err := json.Marshal(content)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
if got := string(data); !strings.Contains(got, `"rich_message":{"html":`) {
|
|
t.Fatalf("unexpected InputRichMessageContent JSON: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestInputRichMessageMediaMarshal(t *testing.T) {
|
|
message := InputRichMessage{
|
|
HTML: `<video src="tg://video?id=intro"></video>`,
|
|
Media: []InputRichMessageMedia{{
|
|
ID: "intro",
|
|
Media: InputMedia{Type: InputMediaTypeVideo, Media: "attach://intro"},
|
|
}},
|
|
}
|
|
data, err := json.Marshal(message)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
|
|
var got struct {
|
|
Media []struct {
|
|
ID string `json:"id"`
|
|
Media InputMedia `json:"media"`
|
|
} `json:"media"`
|
|
}
|
|
if err := json.Unmarshal(data, &got); err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if len(got.Media) != 1 || got.Media[0].ID != "intro" {
|
|
t.Fatalf("unexpected media: %+v", got.Media)
|
|
}
|
|
if got.Media[0].Media.Type != InputMediaTypeVideo || got.Media[0].Media.Media != "attach://intro" {
|
|
t.Fatalf("unexpected embedded media: %+v", got.Media[0].Media)
|
|
}
|
|
}
|
|
|
|
func TestEphemeralMethodsMarshalReceiverUserID(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
params any
|
|
}{
|
|
{"edit text", EditEphemeralMessageText{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3, Text: "updated"}},
|
|
{"edit media", EditEphemeralMessageMedia{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3, Media: InputMedia{Type: InputMediaTypePhoto, Media: "photo-id"}}},
|
|
{"edit caption", EditEphemeralMessageCaption{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3, Caption: "updated"}},
|
|
{"edit markup", EditEphemeralMessageReplyMarkup{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3}},
|
|
{"delete", DeleteEphemeralMessage{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3}},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data, err := json.Marshal(tt.params)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
var fields map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &fields); err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if _, ok := fields["receiver_user_id"]; !ok {
|
|
t.Fatalf("receiver_user_id is missing from %s", data)
|
|
}
|
|
if _, ok := fields["reciever_user_id"]; ok {
|
|
t.Fatalf("misspelled receiver_user_id is present in %s", data)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEphemeralSendParametersMarshal(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
params any
|
|
}{
|
|
{"message", SendMessage{ChatID: 1, Text: "text", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"animation", SendAnimation{ChatID: 1, Animation: "animation", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"audio", SendAudio{ChatID: 1, Audio: "audio", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"document", SendDocument{ChatID: 1, Document: "document", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"photo", SendPhoto{ChatID: 1, Photo: "photo", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"sticker", SendSticker{ChatID: 1, Sticker: "sticker", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"video", SendVideo{ChatID: 1, Video: "video", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"video note", SendVideoNote{ChatID: 1, VideoNote: "video-note", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"voice", SendVoice{ChatID: 1, Voice: "voice", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"contact", SendContact{ChatID: 1, PhoneNumber: "+10000000000", FirstName: "A", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"location", SendLocation{ChatID: 1, Latitude: 1, Longitude: 2, EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
{"venue", SendVenue{ChatID: 1, Latitude: 1, Longitude: 2, Title: "Venue", Address: "Address", EphemeralMessageParameters: &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}}},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data, err := json.Marshal(tt.params)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
var fields map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &fields); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, old := fields["receiver_user_id"]; old {
|
|
t.Fatalf("legacy receiver field remains: %s", data)
|
|
}
|
|
if _, old := fields["callback_query_id"]; old {
|
|
t.Fatalf("legacy callback field remains: %s", data)
|
|
}
|
|
if len(fields["ephemeral_message_parameters"]) == 0 {
|
|
t.Fatalf("missing nested parameters: %s", data)
|
|
}
|
|
if !strings.Contains(string(data), `"receiver_user_id":2`) || !strings.Contains(string(data), `"callback_query_id":"callback"`) {
|
|
t.Fatalf("missing ephemeral parameters in %s", data)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEphemeralUploadParametersMarshal(t *testing.T) {
|
|
ephemeral := &EphemeralMessageParameters{ReceiverUserID: 2, CallbackQueryID: "callback"}
|
|
cases := []struct {
|
|
name string
|
|
params any
|
|
}{
|
|
{"photo", UploadPhoto{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"animation", UploadAnimation{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"audio", UploadAudio{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"document", UploadDocument{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"live photo", UploadLivePhoto{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"video", UploadVideo{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"video note", UploadVideoNote{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
{"voice", UploadVoice{ChatID: 1, EphemeralMessageParameters: ephemeral}},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data, err := json.Marshal(tt.params)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
var fields map[string]json.RawMessage
|
|
if err := json.Unmarshal(data, &fields); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, old := fields["receiver_user_id"]; old {
|
|
t.Fatalf("legacy receiver field remains: %s", data)
|
|
}
|
|
if _, old := fields["callback_query_id"]; old {
|
|
t.Fatalf("legacy callback field remains: %s", data)
|
|
}
|
|
if !strings.Contains(string(fields["ephemeral_message_parameters"]), `"receiver_user_id":2`) {
|
|
t.Fatalf("missing nested parameters: %s", data)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBotAPI103KeyboardAndAdministratorFieldsMarshal(t *testing.T) {
|
|
trueValue := true
|
|
cases := []struct {
|
|
name string
|
|
value any
|
|
fields []string
|
|
}{
|
|
{"inline keyboard force reply", InlineKeyboardMarkup{ForceReply: true}, []string{`"force_reply":true`}},
|
|
{"reply keyboard force reply", ReplyKeyboardMarkup{Keyboard: [][]KeyboardButton{}, ForceReply: true}, []string{`"force_reply":true`}},
|
|
{"disabled inline button", InlineKeyboardButton{Text: "Wait", Disabled: &DisabledButton{}}, []string{`"disabled":{}`}},
|
|
{"administrator member", ChatMember{CanSendWelcomeMessages: &trueValue}, []string{`"can_send_welcome_messages":true`}},
|
|
{"administrator rights", ChatAdministratorRights{CanSendWelcomeMessages: &trueValue}, []string{`"can_send_welcome_messages":true`}},
|
|
{"promote administrator", PromoteChatMember{ChatID: 1, UserID: 2, CanSendWelcomeMessages: true}, []string{`"can_send_welcome_messages":true`}},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data, err := json.Marshal(tt.value)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
for _, field := range tt.fields {
|
|
if !strings.Contains(string(data), field) {
|
|
t.Fatalf("missing %s in %s", field, data)
|
|
}
|
|
}
|
|
if strings.Contains(string(data), "melcome") {
|
|
t.Fatalf("misspelled welcome field in %s", data)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMessageGenerationStoppedUpdateUnmarshal(t *testing.T) {
|
|
var update Update
|
|
err := json.Unmarshal([]byte(`{"update_id":1,"stopped_message_generation":{"chat":{"id":42,"type":"private"},"message_thread_id":3,"draft_id":7}}`), &update)
|
|
if err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if update.Type != UpdateTypeMessageGenerationStopped || update.StoppedMessageGeneration == nil {
|
|
t.Fatalf("unexpected update routing: type=%q payload=%+v", update.Type, update.StoppedMessageGeneration)
|
|
}
|
|
if update.StoppedMessageGeneration.Chat.ID != 42 || update.StoppedMessageGeneration.DraftID != 7 {
|
|
t.Fatalf("unexpected stopped-generation payload: %+v", update.StoppedMessageGeneration)
|
|
}
|
|
}
|
|
|
|
func TestBotAPI103AdditionalFieldsMarshal(t *testing.T) {
|
|
params := []struct {
|
|
name string
|
|
value any
|
|
want []string
|
|
}{
|
|
{
|
|
"ephemeral replacement",
|
|
EphemeralMessageParameters{ReceiverUserID: 2, ReplaceCallbackQueryMessage: true},
|
|
[]string{`"receiver_user_id":2`, `"replace_callback_query_message":true`},
|
|
},
|
|
{
|
|
"message draft controls",
|
|
SendMessageDraft{ChatID: 1, DraftID: 7, CanStop: true, KeepOnStop: true},
|
|
[]string{`"can_stop":true`, `"keep_on_stop":true`},
|
|
},
|
|
{
|
|
"ephemeral rich text",
|
|
EditEphemeralMessageText{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3, RichMessage: &InputRichMessage{HTML: "<b>x</b>"}},
|
|
[]string{`"rich_message":{`, `"html":`},
|
|
},
|
|
{
|
|
"ephemeral caption position",
|
|
EditEphemeralMessageCaption{ChatID: 1, ReceiverUserID: 2, EphemeralMessageID: 3, ShowCaptionAboveMedia: true},
|
|
[]string{`"show_caption_above_media":true`},
|
|
},
|
|
{
|
|
"unique gift privacy",
|
|
UniqueGiftInfo{Text: "gift", Entities: []MessageEntity{{Type: MessageEntityBold, Length: 4}}, IsPrivate: true},
|
|
[]string{`"text":"gift"`, `"entities":[`, `"is_private":true`},
|
|
},
|
|
}
|
|
|
|
for _, tt := range params {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
data, err := json.Marshal(tt.value)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
for _, want := range tt.want {
|
|
if !strings.Contains(string(data), want) {
|
|
t.Fatalf("missing %s in %s", want, data)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInputPollOptionMediaLinkMarshal(t *testing.T) {
|
|
media := InputPollOptionMedia{Type: "link", URL: "https://example.com"}
|
|
data, err := json.Marshal(media)
|
|
if err != nil {
|
|
t.Fatalf("Marshal returned error: %v", err)
|
|
}
|
|
got := string(data)
|
|
if got != `{"type":"link","url":"https://example.com"}` {
|
|
t.Fatalf("unexpected link media JSON: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestPollMediaUnmarshalLink(t *testing.T) {
|
|
var media PollMedia
|
|
if err := json.Unmarshal([]byte(`{"link":{"url":"https://example.com"}}`), &media); err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if media.Link == nil || media.Link.URL != "https://example.com" {
|
|
t.Fatalf("unexpected poll media link: %+v", media.Link)
|
|
}
|
|
}
|
|
|
|
func TestChatJoinRequestUnmarshalQueryID(t *testing.T) {
|
|
payload := `{"chat":{"id":1},"from":{"id":2,"first_name":"A"},"user_chat_id":2,"date":3,"query_id":"q42"}`
|
|
var req ChatJoinRequest
|
|
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if req.QueryID == nil || *req.QueryID != "q42" {
|
|
t.Fatalf("unexpected query_id: %+v", req.QueryID)
|
|
}
|
|
}
|
|
|
|
func TestAnswerChatJoinRequestQueryResultValues(t *testing.T) {
|
|
if JoinRequestApprove != "approve" || JoinRequestDecline != "decline" || JoinRequestQueue != "queue" {
|
|
t.Fatalf("unexpected join request query result values: %q %q %q",
|
|
JoinRequestApprove, JoinRequestDecline, JoinRequestQueue)
|
|
}
|
|
}
|
|
|
|
func TestUserUnmarshalSupportsJoinRequestQueries(t *testing.T) {
|
|
var user User
|
|
if err := json.Unmarshal([]byte(`{"id":1,"first_name":"A","supports_join_request_queries":true}`), &user); err != nil {
|
|
t.Fatalf("Unmarshal returned error: %v", err)
|
|
}
|
|
if user.SupportsJoinRequestQueries == nil || !*user.SupportsJoinRequestQueries {
|
|
t.Fatalf("unexpected supports_join_request_queries: %+v", user.SupportsJoinRequestQueries)
|
|
}
|
|
}
|