owpengram-server/internal/app/bots/stickersbot_test.go

651 lines
25 KiB
Go

package bots
import (
"context"
"strings"
"testing"
"telesrv/internal/domain"
"telesrv/internal/store/memory"
)
func sendTextToStickers(t *testing.T, svc *Service, messages *memory.MessageStore, owner domain.User, text string) string {
t.Helper()
return sendMessageToStickers(t, svc, messages, owner, domain.Message{Body: text})
}
func sendDocumentToStickers(t *testing.T, svc *Service, messages *memory.MessageStore, owner domain.User, doc domain.Document) string {
t.Helper()
return sendMessageToStickers(t, svc, messages, owner, domain.Message{
Media: &domain.MessageMedia{
Kind: domain.MessageMediaKindDocument,
Document: &doc,
},
})
}
func sendMessageToStickers(t *testing.T, svc *Service, messages *memory.MessageStore, owner domain.User, msg domain.Message) string {
t.Helper()
msg.From = domain.Peer{Type: domain.PeerTypeUser, ID: owner.ID}
msg.Peer = domain.Peer{Type: domain.PeerTypeUser, ID: domain.StickersBotUserID}
svc.respondAsStickers(owner.ID, msg)
return latestStickersReply(t, messages, owner.ID).Body
}
func latestStickersReply(t *testing.T, messages *memory.MessageStore, userID int64) domain.Message {
t.Helper()
list, err := messages.ListByUser(context.Background(), userID, domain.MessageFilter{
HasPeer: true,
Peer: domain.Peer{Type: domain.PeerTypeUser, ID: domain.StickersBotUserID},
Limit: 100,
})
if err != nil {
t.Fatalf("list stickers history: %v", err)
}
var latest domain.Message
for _, msg := range list.Messages {
if msg.From.ID == domain.StickersBotUserID && msg.ID > latest.ID {
latest = msg
}
}
if latest.ID == 0 {
t.Fatal("no Stickers reply")
}
return latest
}
func newStickersBotTestService(t *testing.T) (*Service, *memory.UserStore, *memory.BotStore, *memory.MessageStore, *stickersBotFakeCreator, *stickersBotFakeInstaller) {
t.Helper()
users := memory.NewUserStore()
bots := memory.NewBotStore(users)
dialogs := memory.NewDialogStore()
messages := memory.NewMessageStore(dialogs)
creator := &stickersBotFakeCreator{}
installer := &stickersBotFakeInstaller{}
svc := NewService(users, bots, messages, WithStickerSetCreator(creator), WithUserStickerSets(installer))
return svc, users, bots, messages, creator, installer
}
func stickerBotTestDocument(id, accessHash int64, attr domain.DocumentAttributeKind) domain.Document {
return domain.Document{
ID: id,
AccessHash: accessHash,
DCID: 2,
MimeType: "image/webp",
Attributes: []domain.DocumentAttribute{{Kind: attr}},
}
}
func stickerBotUploadDocument(id, accessHash int64, mimeType, fileName string) domain.Document {
return domain.Document{
ID: id,
AccessHash: accessHash,
DCID: 2,
MimeType: mimeType,
Size: 4096,
Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrFilename, FileName: fileName}},
}
}
func stickerBotSetDocument(id, accessHash, setID, setAccessHash int64) domain.Document {
return domain.Document{
ID: id,
AccessHash: accessHash,
DCID: 2,
MimeType: "image/webp",
Attributes: []domain.DocumentAttribute{{
Kind: domain.DocAttrSticker,
StickerSetID: setID,
StickerSetAccessHash: setAccessHash,
}},
}
}
func stickerBotSetCustomEmojiDocument(id, accessHash, setID, setAccessHash int64) domain.Document {
return domain.Document{
ID: id,
AccessHash: accessHash,
DCID: 2,
MimeType: "application/x-tgsticker",
Attributes: []domain.DocumentAttribute{{
Kind: domain.DocAttrCustomEmoji,
StickerSetID: setID,
StickerSetAccessHash: setAccessHash,
}},
}
}
func TestStickersBotSystemSeedStartAndCancel(t *testing.T) {
svc, users, bots, messages, _, _ := newStickersBotTestService(t)
owner := newOwner(t, users, "+3000")
ctx := context.Background()
if !svc.HandlesBot(domain.BotFatherUserID) || !svc.HandlesBot(domain.StickersBotUserID) {
t.Fatal("service should handle BotFather and Stickers")
}
u, found, err := users.ByUsername(ctx, "Stickers")
if err != nil || !found {
t.Fatalf("@Stickers user not seeded: found=%v err=%v", found, err)
}
if u.ID != domain.StickersBotUserID || !u.Bot || u.BotInfoVersion < 1 {
t.Fatalf("@Stickers user = %+v, want seeded bot", u)
}
profile, found, err := bots.GetBot(ctx, domain.StickersBotUserID)
if err != nil || !found {
t.Fatalf("@Stickers profile not seeded: found=%v err=%v", found, err)
}
if !botCommandExists(profile.Commands, "newpack") || !botCommandExists(profile.Commands, "newemoji") ||
!botCommandExists(profile.Commands, "publish") || !botCommandExists(profile.Commands, "addsticker") ||
!botCommandExists(profile.Commands, "delsticker") {
t.Fatalf("@Stickers commands = %+v, want newpack/newemoji/publish/addsticker/delsticker", profile.Commands)
}
if reply := sendTextToStickers(t, svc, messages, owner, "/start"); !strings.Contains(reply, "/newpack") || !strings.Contains(reply, "/newemoji") || !strings.Contains(reply, "/addsticker") {
t.Fatalf("/start reply = %q, want help text", reply)
}
startReply := latestStickersReply(t, messages, owner.ID)
assertReplyEntityText(t, startReply, domain.MessageEntityBotCommand, "/newpack")
assertReplyEntityText(t, startReply, domain.MessageEntityBotCommand, "/newemoji")
assertReplyEntityText(t, startReply, domain.MessageEntityBotCommand, "/addsticker")
sendTextToStickers(t, svc, messages, owner, "/newpack")
if reply := sendTextToStickers(t, svc, messages, owner, "/cancel"); !strings.Contains(reply, "Cancelled") {
t.Fatalf("/cancel reply = %q, want cancelled", reply)
}
if _, found, _ := bots.GetBotChatState(ctx, domain.StickersBotUserID, owner.ID); found {
t.Fatal("stickers bot state still present after /cancel")
}
}
func TestStickersBotNewPackNoMaterialAndInvalidEmoji(t *testing.T) {
svc, users, _, messages, creator, _ := newStickersBotTestService(t)
owner := newOwner(t, users, "+3001")
if reply := sendTextToStickers(t, svc, messages, owner, "/newpack"); !strings.Contains(reply, "sticker pack") {
t.Fatalf("/newpack reply = %q, want sticker pack prompt", reply)
}
if reply := sendTextToStickers(t, svc, messages, owner, "My Pack"); !strings.Contains(reply, "Lottie JSON") {
t.Fatalf("title reply = %q, want document prompt", reply)
}
if reply := sendTextToStickers(t, svc, messages, owner, "/publish"); !strings.Contains(reply, "Add at least one") {
t.Fatalf("empty publish reply = %q, want no material notice", reply)
}
if reply := sendTextToStickers(t, svc, messages, owner, "not a document"); !strings.Contains(reply, "WebM/MP4 must include video metadata") {
t.Fatalf("text in document step reply = %q, want material prompt", reply)
}
if reply := sendDocumentToStickers(t, svc, messages, owner, stickerBotTestDocument(101, 1101, domain.DocAttrSticker)); !strings.Contains(reply, "emoji") {
t.Fatalf("document reply = %q, want emoji prompt", reply)
}
if reply := sendTextToStickers(t, svc, messages, owner, "notemoji"); !strings.Contains(reply, "valid emoji") {
t.Fatalf("invalid emoji reply = %q, want emoji validation", reply)
}
if len(creator.created) != 0 {
t.Fatalf("creator called before valid publish: %+v", creator.created)
}
}
func TestStickersBotPublishStickerPack(t *testing.T) {
svc, users, bots, messages, creator, installer := newStickersBotTestService(t)
hooks := &stickersBotHookRecorder{}
svc.SetRouterHooks(hooks)
owner := newOwner(t, users, "+3002")
sendTextToStickers(t, svc, messages, owner, "/newpack")
sendTextToStickers(t, svc, messages, owner, "Fresh Pack")
sendDocumentToStickers(t, svc, messages, owner, stickerBotTestDocument(201, 2201, domain.DocAttrSticker))
sendTextToStickers(t, svc, messages, owner, "🙂")
sendTextToStickers(t, svc, messages, owner, "/publish")
reply := sendTextToStickers(t, svc, messages, owner, "fresh_pack")
if !strings.Contains(reply, "https://telesrv.net/addstickers/fresh_pack") {
t.Fatalf("publish reply = %q, want addstickers link", reply)
}
publishReply := latestStickersReply(t, messages, owner.ID)
assertReplyEntityText(t, publishReply, domain.MessageEntityURL, "https://telesrv.net/addstickers/fresh_pack")
if len(creator.created) != 1 {
t.Fatalf("created requests = %d, want 1", len(creator.created))
}
req := creator.created[0]
if req.CreatorUserID != owner.ID || req.Title != "Fresh Pack" || req.ShortName != "fresh_pack" || req.Kind != domain.StickerSetKindStickers {
t.Fatalf("create request = %+v, want owner/title/short/kind", req)
}
if len(req.Items) != 1 || req.Items[0].DocumentID != 201 || req.Items[0].DocumentAccessHash != 2201 || req.Items[0].Emoji != "🙂" {
t.Fatalf("create items = %+v, want doc+emoji", req.Items)
}
if len(installer.installs) != 1 || installer.installs[0].userID != owner.ID || installer.installs[0].setID != creator.sets[0].ID {
t.Fatalf("installs = %+v, want creator install", installer.installs)
}
if hooks.userID != owner.ID || hooks.kind != domain.StickerSetKindStickers {
t.Fatalf("sticker update hook = user %d kind %q, want creator stickers", hooks.userID, hooks.kind)
}
if _, found, _ := bots.GetBotChatState(context.Background(), domain.StickersBotUserID, owner.ID); found {
t.Fatal("stickers bot state still present after publish")
}
}
func TestStickersBotPublishUploadedTGS(t *testing.T) {
svc, users, _, messages, creator, installer := newStickersBotTestService(t)
owner := newOwner(t, users, "+3004")
sendTextToStickers(t, svc, messages, owner, "/newemoji")
sendTextToStickers(t, svc, messages, owner, "Local Emoji")
reply := sendDocumentToStickers(t, svc, messages, owner, stickerBotUploadDocument(401, 4401, "application/octet-stream", "wave.tgs"))
if !strings.Contains(reply, "emoji") {
t.Fatalf("uploaded tgs reply = %q, want emoji prompt", reply)
}
sendTextToStickers(t, svc, messages, owner, "👋")
sendTextToStickers(t, svc, messages, owner, "/publish")
reply = sendTextToStickers(t, svc, messages, owner, "local_emoji")
if !strings.Contains(reply, "https://telesrv.net/addemoji/local_emoji") {
t.Fatalf("publish uploaded tgs reply = %q, want addemoji link", reply)
}
if len(creator.created) != 1 {
t.Fatalf("created requests = %d, want 1", len(creator.created))
}
req := creator.created[0]
if req.Kind != domain.StickerSetKindEmoji || len(req.Items) != 1 || req.Items[0].DocumentID != 401 || req.Items[0].DocumentAccessHash != 4401 {
t.Fatalf("create request = %+v, want uploaded tgs item in emoji pack", req)
}
if len(installer.installs) != 1 || installer.installs[0].kind != domain.StickerSetKindEmoji {
t.Fatalf("installs = %+v, want emoji install", installer.installs)
}
}
func TestStickersBotPublishUploadedLottieJSON(t *testing.T) {
svc, users, _, messages, creator, installer := newStickersBotTestService(t)
owner := newOwner(t, users, "+3005")
sendTextToStickers(t, svc, messages, owner, "/newpack")
sendTextToStickers(t, svc, messages, owner, "Lottie Pack")
reply := sendDocumentToStickers(t, svc, messages, owner, stickerBotUploadDocument(402, 4402, "application/json", "wave.json"))
if !strings.Contains(reply, "emoji") {
t.Fatalf("uploaded lottie reply = %q, want emoji prompt", reply)
}
sendTextToStickers(t, svc, messages, owner, "👋")
sendTextToStickers(t, svc, messages, owner, "/publish")
reply = sendTextToStickers(t, svc, messages, owner, "lottie_pack")
if !strings.Contains(reply, "https://telesrv.net/addstickers/lottie_pack") {
t.Fatalf("publish uploaded lottie reply = %q, want addstickers link", reply)
}
if len(creator.created) != 1 {
t.Fatalf("created requests = %d, want 1", len(creator.created))
}
req := creator.created[0]
if req.Kind != domain.StickerSetKindStickers || len(req.Items) != 1 || req.Items[0].DocumentID != 402 || req.Items[0].DocumentAccessHash != 4402 {
t.Fatalf("create request = %+v, want uploaded lottie item in sticker pack", req)
}
if len(installer.installs) != 1 || installer.installs[0].kind != domain.StickerSetKindStickers {
t.Fatalf("installs = %+v, want sticker install", installer.installs)
}
}
func TestStickersBotPublishCustomEmojiPack(t *testing.T) {
svc, users, _, messages, creator, installer := newStickersBotTestService(t)
owner := newOwner(t, users, "+3003")
sendTextToStickers(t, svc, messages, owner, "/newemoji")
sendTextToStickers(t, svc, messages, owner, "Emoji Pack")
sendDocumentToStickers(t, svc, messages, owner, stickerBotTestDocument(301, 3301, domain.DocAttrCustomEmoji))
sendTextToStickers(t, svc, messages, owner, "🔥")
sendTextToStickers(t, svc, messages, owner, "/publish")
reply := sendTextToStickers(t, svc, messages, owner, "emoji_pack")
if !strings.Contains(reply, "https://telesrv.net/addemoji/emoji_pack") {
t.Fatalf("publish emoji reply = %q, want addemoji link", reply)
}
if len(creator.created) != 1 || creator.created[0].Kind != domain.StickerSetKindEmoji {
t.Fatalf("created emoji requests = %+v, want kind emoji", creator.created)
}
if len(installer.installs) != 1 || installer.installs[0].kind != domain.StickerSetKindEmoji {
t.Fatalf("emoji installs = %+v, want emoji kind install", installer.installs)
}
}
func TestStickersBotAddStickerToExistingPack(t *testing.T) {
svc, users, bots, messages, manager, _ := newStickersBotTestService(t)
hooks := &stickersBotHookRecorder{}
svc.SetRouterHooks(hooks)
owner := newOwner(t, users, "+3006")
manager.sets = append(manager.sets, domain.StickerSet{
ID: 7100,
AccessHash: 8100,
ShortName: "fresh_pack",
Title: "Fresh Pack",
Kind: domain.StickerSetKindStickers,
Creator: true,
CreatorUserID: owner.ID,
Count: 1,
DocumentIDs: []int64{501},
})
if reply := sendTextToStickers(t, svc, messages, owner, "/addsticker"); !strings.Contains(reply, "short name") {
t.Fatalf("/addsticker reply = %q, want short name prompt", reply)
}
if reply := sendTextToStickers(t, svc, messages, owner, "https://telesrv.net/addstickers/fresh_pack"); !strings.Contains(reply, "Selected Fresh Pack") {
t.Fatalf("select pack reply = %q, want selected pack", reply)
}
if reply := sendDocumentToStickers(t, svc, messages, owner, stickerBotUploadDocument(502, 5502, "application/json", "new.json")); !strings.Contains(reply, "emoji") {
t.Fatalf("add document reply = %q, want emoji prompt", reply)
}
reply := sendTextToStickers(t, svc, messages, owner, "😄")
if !strings.Contains(reply, "Done. Added to Fresh Pack") || !strings.Contains(reply, "https://telesrv.net/addstickers/fresh_pack") {
t.Fatalf("add final reply = %q, want done link", reply)
}
if len(manager.adds) != 1 {
t.Fatalf("adds = %+v, want one add", manager.adds)
}
add := manager.adds[0]
if add.userID != owner.ID || add.ref.ID != 7100 || add.item.DocumentID != 502 || add.item.DocumentAccessHash != 5502 || add.item.Emoji != "😄" {
t.Fatalf("add call = %+v, want owner/set/doc/emoji", add)
}
if hooks.userID != owner.ID || hooks.kind != domain.StickerSetKindStickers {
t.Fatalf("hook = user %d kind %q, want owner stickers", hooks.userID, hooks.kind)
}
if _, found, _ := bots.GetBotChatState(context.Background(), domain.StickersBotUserID, owner.ID); found {
t.Fatal("stickers bot state still present after add")
}
}
func TestStickersBotAddStickerDuplicateStaysInFlow(t *testing.T) {
svc, users, bots, messages, manager, _ := newStickersBotTestService(t)
owner := newOwner(t, users, "+3008")
manager.sets = append(manager.sets, domain.StickerSet{
ID: 7300,
AccessHash: 8300,
ShortName: "fresh_pack",
Title: "Fresh Pack",
Kind: domain.StickerSetKindStickers,
CreatorUserID: owner.ID,
Count: 1,
DocumentIDs: []int64{501},
})
sendTextToStickers(t, svc, messages, owner, "/addsticker")
sendTextToStickers(t, svc, messages, owner, "fresh_pack")
sendDocumentToStickers(t, svc, messages, owner, stickerBotSetDocument(501, 5501, 7300, 8300))
reply := sendTextToStickers(t, svc, messages, owner, "😄")
if !strings.Contains(reply, "already in this pack") {
t.Fatalf("duplicate add reply = %q, want already-in-pack notice", reply)
}
if len(manager.adds) != 0 {
t.Fatalf("adds = %+v, want no manager add for duplicate", manager.adds)
}
state, found, _ := bots.GetBotChatState(context.Background(), domain.StickersBotUserID, owner.ID)
if !found || state.Step != stickersBotStepDocument {
t.Fatalf("state after duplicate = %+v found=%v, want document step", state, found)
}
}
func TestStickersBotDeleteStickerFromExistingPack(t *testing.T) {
svc, users, bots, messages, manager, _ := newStickersBotTestService(t)
hooks := &stickersBotHookRecorder{}
svc.SetRouterHooks(hooks)
owner := newOwner(t, users, "+3007")
manager.sets = append(manager.sets, domain.StickerSet{
ID: 7200,
AccessHash: 8200,
ShortName: "old_pack",
Title: "Old Pack",
Kind: domain.StickerSetKindStickers,
Creator: true,
CreatorUserID: owner.ID,
Count: 2,
DocumentIDs: []int64{601, 602},
})
sendTextToStickers(t, svc, messages, owner, "/delsticker")
if reply := sendTextToStickers(t, svc, messages, owner, "old_pack"); !strings.Contains(reply, "Selected Old Pack") {
t.Fatalf("select delete pack reply = %q, want selected pack", reply)
}
doc := stickerBotSetDocument(601, 6601, 7200, 8200)
reply := sendDocumentToStickers(t, svc, messages, owner, doc)
if !strings.Contains(reply, "Done. Removed from Old Pack") || !strings.Contains(reply, "https://telesrv.net/addstickers/old_pack") {
t.Fatalf("delete final reply = %q, want done link", reply)
}
if len(manager.removes) != 1 || manager.removes[0].documentID != 601 || manager.removes[0].accessHash != 6601 {
t.Fatalf("removes = %+v, want document 601", manager.removes)
}
if hooks.userID != owner.ID || hooks.kind != domain.StickerSetKindStickers {
t.Fatalf("hook = user %d kind %q, want owner stickers", hooks.userID, hooks.kind)
}
if _, found, _ := bots.GetBotChatState(context.Background(), domain.StickersBotUserID, owner.ID); found {
t.Fatal("stickers bot state still present after delete")
}
}
func TestStickersBotDeleteCustomEmojiEntityFromExistingPack(t *testing.T) {
svc, users, bots, messages, manager, _ := newStickersBotTestService(t)
owner := newOwner(t, users, "+3009")
manager.sets = append(manager.sets, domain.StickerSet{
ID: 7400,
AccessHash: 8400,
ShortName: "emoji_pack",
Title: "Emoji Pack",
Kind: domain.StickerSetKindEmoji,
Emojis: true,
CreatorUserID: owner.ID,
Count: 2,
DocumentIDs: []int64{701, 702},
})
manager.docs = map[int64]domain.Document{
701: stickerBotSetCustomEmojiDocument(701, 7701, 7400, 8400),
}
sendTextToStickers(t, svc, messages, owner, "/delsticker")
sendTextToStickers(t, svc, messages, owner, "emoji_pack")
reply := sendMessageToStickers(t, svc, messages, owner, domain.Message{
Body: "🔥",
Entities: []domain.MessageEntity{{
Type: domain.MessageEntityCustomEmoji,
Offset: 0,
Length: 2,
DocumentID: 701,
}},
})
if !strings.Contains(reply, "Done. Removed from Emoji Pack") || !strings.Contains(reply, "https://telesrv.net/addemoji/emoji_pack") {
t.Fatalf("delete custom emoji reply = %q, want done emoji link", reply)
}
if len(manager.removes) != 1 || manager.removes[0].documentID != 701 || manager.removes[0].accessHash != 7701 {
t.Fatalf("removes = %+v, want custom emoji document 701", manager.removes)
}
if _, found, _ := bots.GetBotChatState(context.Background(), domain.StickersBotUserID, owner.ID); found {
t.Fatal("stickers bot state still present after custom emoji delete")
}
}
func botCommandExists(commands []domain.BotCommand, want string) bool {
for _, c := range commands {
if c.Command == want {
return true
}
}
return false
}
func assertReplyEntityText(t *testing.T, msg domain.Message, typ domain.MessageEntityType, want string) {
t.Helper()
for _, entity := range msg.Entities {
if entity.Type != typ {
continue
}
if entity.Offset < 0 || entity.Length < 0 || entity.Offset+entity.Length > len(msg.Body) {
t.Fatalf("entity %+v out of ASCII bounds for %q", entity, msg.Body)
}
if got := msg.Body[entity.Offset : entity.Offset+entity.Length]; got == want {
return
}
}
t.Fatalf("message %q entities %+v missing %s entity for %q", msg.Body, msg.Entities, typ, want)
}
type stickersBotFakeCreator struct {
created []domain.CreateStickerSetRequest
sets []domain.StickerSet
docs map[int64]domain.Document
adds []stickersBotAdd
removes []stickersBotRemove
}
type stickersBotAdd struct {
userID int64
ref domain.StickerSetRef
item domain.StickerSetItemInput
}
type stickersBotRemove struct {
userID int64
documentID int64
accessHash int64
}
func (f *stickersBotFakeCreator) CreateStickerSet(_ context.Context, req domain.CreateStickerSetRequest) (domain.StickerSet, []domain.Document, error) {
f.created = append(f.created, req)
docIDs := make([]int64, 0, len(req.Items))
for _, item := range req.Items {
docIDs = append(docIDs, item.DocumentID)
}
kind := req.Kind
if kind == "" {
kind = domain.StickerSetKindStickers
}
set := domain.StickerSet{
ID: 7000 + int64(len(f.sets)),
AccessHash: 8000 + int64(len(f.sets)),
ShortName: strings.ToLower(strings.TrimSpace(req.ShortName)),
Title: req.Title,
Kind: kind,
Emojis: kind == domain.StickerSetKindEmoji,
Creator: true,
CreatorUserID: req.CreatorUserID,
Count: len(docIDs),
DocumentIDs: docIDs,
}
f.sets = append(f.sets, set)
return set, nil, nil
}
func (f *stickersBotFakeCreator) ResolveStickerSet(_ context.Context, ref domain.StickerSetRef) (domain.StickerSet, []domain.Document, bool, error) {
idx := f.indexSet(ref)
if idx < 0 {
return domain.StickerSet{}, nil, false, nil
}
return f.sets[idx], nil, true, nil
}
func (f *stickersBotFakeCreator) ListCreatedStickerSets(_ context.Context, userID int64, _ int64, limit int) ([]domain.StickerSet, int, error) {
var out []domain.StickerSet
for _, set := range f.sets {
if set.CreatorUserID == userID {
out = append(out, set)
}
}
total := len(out)
if limit > 0 && len(out) > limit {
out = out[:limit]
}
return out, total, nil
}
func (f *stickersBotFakeCreator) GetDocuments(_ context.Context, ids []int64) ([]domain.Document, error) {
out := make([]domain.Document, 0, len(ids))
for _, id := range ids {
if doc, ok := f.docs[id]; ok {
out = append(out, doc)
}
}
return out, nil
}
func (f *stickersBotFakeCreator) AddStickerToSet(_ context.Context, actorUserID int64, ref domain.StickerSetRef, item domain.StickerSetItemInput) (domain.StickerSet, []domain.Document, error) {
f.adds = append(f.adds, stickersBotAdd{userID: actorUserID, ref: ref, item: item})
idx := f.indexSet(ref)
if idx < 0 || f.sets[idx].CreatorUserID != actorUserID {
return domain.StickerSet{}, nil, domain.ErrStickerSetInvalid
}
set := f.sets[idx]
if !stickersBotTestContainsInt64(set.DocumentIDs, item.DocumentID) {
set.DocumentIDs = append(set.DocumentIDs, item.DocumentID)
set.Count = len(set.DocumentIDs)
}
f.sets[idx] = set
return set, nil, nil
}
func (f *stickersBotFakeCreator) RemoveStickerFromSet(_ context.Context, actorUserID int64, documentID int64, accessHash int64) (domain.StickerSet, []domain.Document, error) {
f.removes = append(f.removes, stickersBotRemove{userID: actorUserID, documentID: documentID, accessHash: accessHash})
for i, set := range f.sets {
if set.CreatorUserID != actorUserID {
continue
}
for idx, id := range set.DocumentIDs {
if id != documentID {
continue
}
set.DocumentIDs = append(append([]int64(nil), set.DocumentIDs[:idx]...), set.DocumentIDs[idx+1:]...)
set.Count = len(set.DocumentIDs)
f.sets[i] = set
return set, nil, nil
}
}
return domain.StickerSet{}, nil, domain.ErrStickerSetFileInvalid
}
func (f *stickersBotFakeCreator) indexSet(ref domain.StickerSetRef) int {
for i, set := range f.sets {
switch ref.Kind {
case domain.StickerSetRefByID:
if set.ID == ref.ID && (ref.AccessHash == 0 || set.AccessHash == ref.AccessHash) {
return i
}
case domain.StickerSetRefByShortName:
if strings.EqualFold(set.ShortName, ref.ShortName) {
return i
}
}
}
return -1
}
func stickersBotTestContainsInt64(values []int64, want int64) bool {
for _, value := range values {
if value == want {
return true
}
}
return false
}
type stickersBotFakeInstaller struct {
installs []stickersBotInstall
}
type stickersBotInstall struct {
userID int64
setID int64
kind domain.StickerSetKind
}
func (f *stickersBotFakeInstaller) InstallUserStickerSet(_ context.Context, userID int64, setID int64, kind domain.StickerSetKind, _ bool, _ int) error {
f.installs = append(f.installs, stickersBotInstall{userID: userID, setID: setID, kind: kind})
return nil
}
type stickersBotHookRecorder struct {
userID int64
kind domain.StickerSetKind
}
func (h *stickersBotHookRecorder) RevokeBotSessions(context.Context, int64) error {
return nil
}
func (h *stickersBotHookRecorder) PushBotCommandsChanged(context.Context, int64, []domain.BotCommand) {
}
func (h *stickersBotHookRecorder) PushStickerSetsChanged(_ context.Context, userID int64, kind domain.StickerSetKind) {
h.userID = userID
h.kind = kind
}