728 lines
27 KiB
Go
728 lines
27 KiB
Go
package tdesktop
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/iamxvbaba/td/tg"
|
|
|
|
"telesrv/internal/seed/appearance"
|
|
)
|
|
|
|
func TestNotifySettingsDefaultIsAudible(t *testing.T) {
|
|
settings := NotifySettings()
|
|
if value, ok := settings.GetShowPreviews(); !ok || !value {
|
|
t.Fatalf("show_previews = %v ok=%v, want true", value, ok)
|
|
}
|
|
if value, ok := settings.GetSilent(); !ok || value {
|
|
t.Fatalf("silent = %v ok=%v, want explicit false", value, ok)
|
|
}
|
|
if value, ok := settings.GetMuteUntil(); !ok || value != 0 {
|
|
t.Fatalf("mute_until = %d ok=%v, want explicit 0", value, ok)
|
|
}
|
|
if value, ok := settings.GetOtherSound(); !ok || value == nil {
|
|
t.Fatalf("other_sound = %#v ok=%v, want default sound", value, ok)
|
|
}
|
|
}
|
|
|
|
func TestTimezonesListIsNonEmptyAndHashable(t *testing.T) {
|
|
got, ok := TimezonesList(0).(*tg.HelpTimezonesList)
|
|
if !ok || got.Hash == 0 || len(got.Timezones) == 0 {
|
|
t.Fatalf("TimezonesList(0) = %#v, want non-empty modified list", got)
|
|
}
|
|
if _, ok := TimezonesList(got.Hash).(*tg.HelpTimezonesListNotModified); !ok {
|
|
t.Fatalf("TimezonesList(hash) = %#v, want notModified", TimezonesList(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestAppConfigIncludesStoryStealthPeriods(t *testing.T) {
|
|
got, ok := AppConfig(0).(*tg.HelpAppConfig)
|
|
if !ok || got.Hash == 0 {
|
|
t.Fatalf("AppConfig(0) = %#v, want modified config with hash", got)
|
|
}
|
|
values := make(map[string]float64)
|
|
strings := make(map[string]string)
|
|
arrays := make(map[string]*tg.JSONArray)
|
|
bools := make(map[string]bool)
|
|
boolSeen := make(map[string]bool)
|
|
if object, ok := got.Config.(*tg.JSONObject); ok && object != nil {
|
|
for _, entry := range object.Value {
|
|
if number, ok := entry.Value.(*tg.JSONNumber); ok {
|
|
values[entry.Key] = number.Value
|
|
}
|
|
if str, ok := entry.Value.(*tg.JSONString); ok {
|
|
strings[entry.Key] = str.Value
|
|
}
|
|
if array, ok := entry.Value.(*tg.JSONArray); ok {
|
|
arrays[entry.Key] = array
|
|
}
|
|
if boolean, ok := entry.Value.(*tg.JSONBool); ok {
|
|
bools[entry.Key] = boolean.Value
|
|
boolSeen[entry.Key] = true
|
|
}
|
|
}
|
|
}
|
|
want := map[string]float64{
|
|
"stories_stealth_future_period": 1500,
|
|
"stories_stealth_past_period": 300,
|
|
"stories_stealth_cooldown_period": 10800,
|
|
"giveaway_boosts_per_premium": 4,
|
|
"giveaway_countries_max": 10,
|
|
"giveaway_add_peers_max": 10,
|
|
"giveaway_period_max": 604800,
|
|
}
|
|
for key, expected := range want {
|
|
if values[key] != expected {
|
|
t.Fatalf("AppConfig[%q] = %v, want %v", key, values[key], expected)
|
|
}
|
|
}
|
|
if strings["rich_message_posting"] != "enabled" {
|
|
t.Fatalf("AppConfig[rich_message_posting] = %q, want enabled", strings["rich_message_posting"])
|
|
}
|
|
if !boolSeen["stars_purchase_blocked"] || bools["stars_purchase_blocked"] ||
|
|
!boolSeen["giveaway_gifts_purchase_available"] || !bools["giveaway_gifts_purchase_available"] {
|
|
t.Fatalf("AppConfig purchase flags = stars_blocked:%v giveaway_available:%v", bools["stars_purchase_blocked"], bools["giveaway_gifts_purchase_available"])
|
|
}
|
|
fragmentPrefixes := arrays["fragment_prefixes"]
|
|
if fragmentPrefixes == nil || len(fragmentPrefixes.Value) != 1 {
|
|
t.Fatalf("AppConfig[fragment_prefixes] = %#v, want one-element array", fragmentPrefixes)
|
|
}
|
|
prefix, ok := fragmentPrefixes.Value[0].(*tg.JSONString)
|
|
if !ok || prefix.Value != "888" {
|
|
t.Fatalf("AppConfig[fragment_prefixes][0] = %#v, want \"888\"", fragmentPrefixes.Value[0])
|
|
}
|
|
directCurrencies := arrays["premium_playmarket_direct_currency_list"]
|
|
if directCurrencies == nil || !tgJSONArrayContainsString(directCurrencies, "USD") {
|
|
t.Fatalf("AppConfig[premium_playmarket_direct_currency_list] = %#v, want USD", directCurrencies)
|
|
}
|
|
if _, ok := AppConfig(got.Hash).(*tg.HelpAppConfigNotModified); !ok {
|
|
t.Fatalf("AppConfig(hash) = %#v, want notModified", AppConfig(got.Hash))
|
|
}
|
|
if _, ok := AppConfig(got.Hash - 1).(*tg.HelpAppConfig); !ok {
|
|
t.Fatalf("AppConfig(old hash) = %#v, want refreshed config", AppConfig(got.Hash-1))
|
|
}
|
|
}
|
|
|
|
func tgJSONArrayContainsString(array *tg.JSONArray, want string) bool {
|
|
for _, value := range array.Value {
|
|
if text, ok := value.(*tg.JSONString); ok && text.Value == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestFallbackAppConfigOmitsMapboxToken(t *testing.T) {
|
|
got, ok := AppConfig(0).(*tg.HelpAppConfig)
|
|
if !ok {
|
|
t.Fatalf("AppConfig(0) = %T, want modified config", got)
|
|
}
|
|
if object, ok := got.Config.(*tg.JSONObject); ok && object != nil {
|
|
for _, entry := range object.Value {
|
|
if entry.Key == "tdesktop_config_map" {
|
|
t.Fatal("fallback AppConfig leaked tdesktop_config_map without runtime token")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAvailableReactionsCatalogIsNonEmptyAndHashable(t *testing.T) {
|
|
got, ok := AvailableReactions(0).(*tg.MessagesAvailableReactions)
|
|
if !ok {
|
|
t.Fatalf("AvailableReactions(0) = %T, want modified list", got)
|
|
}
|
|
if got.Hash == 0 {
|
|
t.Fatal("AvailableReactions(0).Hash = 0, want stable cache hash")
|
|
}
|
|
if len(got.Reactions) == 0 {
|
|
t.Fatal("AvailableReactions(0).Reactions is empty")
|
|
}
|
|
for i, reaction := range got.Reactions {
|
|
if reaction.Reaction == "" {
|
|
t.Fatalf("reaction[%d].Reaction is empty", i)
|
|
}
|
|
if reaction.Title == "" {
|
|
t.Fatalf("reaction[%d].Title is empty", i)
|
|
}
|
|
if reaction.StaticIcon == nil ||
|
|
reaction.AppearAnimation == nil ||
|
|
reaction.SelectAnimation == nil ||
|
|
reaction.ActivateAnimation == nil ||
|
|
reaction.EffectAnimation == nil {
|
|
t.Fatalf("reaction[%d] has nil required document: %#v", i, reaction)
|
|
}
|
|
if reaction.Inactive || reaction.Premium {
|
|
t.Fatalf("reaction[%d] flags = inactive %v premium %v, want active non-premium", i, reaction.Inactive, reaction.Premium)
|
|
}
|
|
}
|
|
if _, ok := AvailableReactions(got.Hash).(*tg.MessagesAvailableReactionsNotModified); !ok {
|
|
t.Fatalf("AvailableReactions(hash) = %#v, want notModified", AvailableReactions(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestChatThemesCatalogIsNonEmptyHashableAndHasQRBackgroundColors(t *testing.T) {
|
|
got, ok := ChatThemes(0).(*tg.AccountThemes)
|
|
if !ok {
|
|
t.Fatalf("ChatThemes(0) = %T, want modified list", got)
|
|
}
|
|
if got.Hash == 0 {
|
|
t.Fatal("ChatThemes(0).Hash = 0, want stable cache hash")
|
|
}
|
|
if len(got.Themes) == 0 {
|
|
t.Fatal("ChatThemes(0).Themes is empty")
|
|
}
|
|
for i, theme := range got.Themes {
|
|
if !theme.GetForChat() {
|
|
t.Fatalf("theme[%d].for_chat = false, want true", i)
|
|
}
|
|
if emoticon, ok := theme.GetEmoticon(); !ok || emoticon == "" || !IsChatThemeEmoticon(emoticon) {
|
|
t.Fatalf("theme[%d].emoticon = %q ok=%v, want supported token", i, emoticon, ok)
|
|
}
|
|
settings, ok := theme.GetSettings()
|
|
// DrKLO only surfaces an emoji chat theme in the picker when it ships
|
|
// settings for at least four base themes
|
|
// (MediaDataController.generateEmojiPreviewThemes drops items.size() < 4,
|
|
// one item per ThemeSettings); fewer leaves the strip stuck on its
|
|
// loading shimmer.
|
|
if !ok || len(settings) < 4 {
|
|
t.Fatalf("theme[%d].settings = %#v ok=%v, want >=4 base-theme settings", i, settings, ok)
|
|
}
|
|
var hasDay, hasNight bool
|
|
for j, setting := range settings {
|
|
if setting.BaseTheme == nil {
|
|
t.Fatalf("theme[%d].settings[%d].base_theme missing", i, j)
|
|
}
|
|
switch setting.BaseTheme.(type) {
|
|
case *tg.BaseThemeDay:
|
|
hasDay = true
|
|
case *tg.BaseThemeNight:
|
|
hasNight = true
|
|
}
|
|
// 官方聊天主题用文档型主题背景墙纸(非旧的纯渐变 WallPaperNoFile),
|
|
// 这里只要求每组设置带一个墙纸。
|
|
if wallpaper, ok := setting.GetWallpaper(); !ok || wallpaper == nil {
|
|
t.Fatalf("theme[%d].settings[%d].wallpaper = %#v ok=%v, want wallpaper", i, j, wallpaper, ok)
|
|
}
|
|
}
|
|
if !hasDay || !hasNight {
|
|
t.Fatalf("theme[%d] settings missing day/night coverage (day=%v night=%v)", i, hasDay, hasNight)
|
|
}
|
|
}
|
|
if _, ok := ChatThemes(got.Hash).(*tg.AccountThemesNotModified); !ok {
|
|
t.Fatalf("ChatThemes(hash) = %#v, want notModified", ChatThemes(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestDefaultThemesAreDefaultFlaggedForPicker(t *testing.T) {
|
|
// account.getThemes feeds DrKLO's "Color theme" preview strip
|
|
// (DefaultThemesPreviewCell), which only consumes themes flagged
|
|
// is_default=true. Returning themesNotModified to a fresh client (hash 0)
|
|
// leaves the strip stuck on a loading shimmer, so a fresh request must
|
|
// return a populated, default-flagged catalog.
|
|
got, ok := DefaultThemes(0).(*tg.AccountThemes)
|
|
if !ok {
|
|
t.Fatalf("DefaultThemes(0) = %T, want modified list", got)
|
|
}
|
|
if got.Hash == 0 {
|
|
t.Fatal("DefaultThemes(0).Hash = 0, want stable cache hash")
|
|
}
|
|
if len(got.Themes) == 0 {
|
|
t.Fatal("DefaultThemes(0).Themes is empty")
|
|
}
|
|
for i, theme := range got.Themes {
|
|
if !theme.GetDefault() {
|
|
t.Fatalf("theme[%d].is_default = false, want true so the picker shows it", i)
|
|
}
|
|
if !theme.GetForChat() {
|
|
t.Fatalf("theme[%d].for_chat = false, want true", i)
|
|
}
|
|
if settings, ok := theme.GetSettings(); !ok || len(settings) < 4 {
|
|
t.Fatalf("theme[%d].settings len=%d ok=%v, want >=4 for the picker", i, len(settings), ok)
|
|
}
|
|
}
|
|
if _, ok := DefaultThemes(got.Hash).(*tg.AccountThemesNotModified); !ok {
|
|
t.Fatalf("DefaultThemes(hash) = %#v, want notModified", DefaultThemes(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestDefaultThemeSettingsFollowDrKLOPickerIndices(t *testing.T) {
|
|
for _, theme := range DefaultThemeList() {
|
|
settings, ok := theme.GetSettings()
|
|
if !ok || len(settings) < 5 {
|
|
t.Fatalf("theme %d settings len=%d ok=%v, want five stable base slots", theme.ID, len(settings), ok)
|
|
}
|
|
if _, ok := settings[0].BaseTheme.(*tg.BaseThemeClassic); !ok {
|
|
t.Fatalf("theme %d settings[0] base = %T, want classic", theme.ID, settings[0].BaseTheme)
|
|
}
|
|
if _, ok := settings[1].BaseTheme.(*tg.BaseThemeDay); !ok {
|
|
t.Fatalf("theme %d settings[1] base = %T, want day", theme.ID, settings[1].BaseTheme)
|
|
}
|
|
if _, ok := settings[2].BaseTheme.(*tg.BaseThemeNight); !ok {
|
|
t.Fatalf("theme %d settings[2] base = %T, want night", theme.ID, settings[2].BaseTheme)
|
|
}
|
|
if _, ok := settings[3].BaseTheme.(*tg.BaseThemeTinted); !ok {
|
|
t.Fatalf("theme %d settings[3] base = %T, want tinted", theme.ID, settings[3].BaseTheme)
|
|
}
|
|
if _, ok := settings[4].BaseTheme.(*tg.BaseThemeArctic); !ok {
|
|
t.Fatalf("theme %d settings[4] base = %T, want arctic", theme.ID, settings[4].BaseTheme)
|
|
}
|
|
wallpaperClass, ok := settings[2].GetWallpaper()
|
|
wallpaper, fileWallpaper := wallpaperClass.(*tg.WallPaper)
|
|
if !ok || !fileWallpaper || !wallpaper.GetDark() {
|
|
t.Fatalf("theme %d night slot wallpaper = %#v ok=%v, want dark file wallpaper", theme.ID, wallpaperClass, ok)
|
|
}
|
|
}
|
|
|
|
if _, ok := ChatThemes(2026062501).(*tg.AccountThemesNotModified); ok {
|
|
t.Fatal("pre-fix chat theme hash was not invalidated after settings reorder")
|
|
}
|
|
}
|
|
|
|
func TestLookupDefaultThemeValidatesIdentity(t *testing.T) {
|
|
themes := DefaultThemeList()
|
|
if len(themes) == 0 {
|
|
t.Fatal("DefaultThemeList is empty")
|
|
}
|
|
for _, theme := range themes {
|
|
byID, ok := LookupDefaultTheme(&tg.InputTheme{
|
|
ID: theme.ID,
|
|
AccessHash: theme.AccessHash,
|
|
})
|
|
if !ok || byID.ID != theme.ID {
|
|
t.Fatalf("lookup id %d = id %d ok=%v, want exact theme", theme.ID, byID.ID, ok)
|
|
}
|
|
bySlug, ok := LookupDefaultTheme(&tg.InputThemeSlug{Slug: theme.Slug})
|
|
if !ok || bySlug.ID != theme.ID {
|
|
t.Fatalf("lookup slug %q = id %d ok=%v, want %d", theme.Slug, bySlug.ID, ok, theme.ID)
|
|
}
|
|
if _, ok := LookupDefaultTheme(&tg.InputTheme{
|
|
ID: theme.ID,
|
|
AccessHash: theme.AccessHash + 1,
|
|
}); ok {
|
|
t.Fatalf("lookup id %d accepted forged access hash", theme.ID)
|
|
}
|
|
}
|
|
if _, ok := LookupDefaultTheme(&tg.InputThemeSlug{}); ok {
|
|
t.Fatal("lookup accepted empty slug")
|
|
}
|
|
}
|
|
|
|
func TestUniqueGiftChatThemesIsEmptyHashableStub(t *testing.T) {
|
|
got, ok := UniqueGiftChatThemes(0).(*tg.AccountChatThemes)
|
|
if !ok {
|
|
t.Fatalf("UniqueGiftChatThemes(0) = %T, want modified list", got)
|
|
}
|
|
if got.Hash == 0 {
|
|
t.Fatal("UniqueGiftChatThemes(0).Hash = 0, want stable cache hash")
|
|
}
|
|
if len(got.Themes) != 0 || len(got.Chats) != 0 || len(got.Users) != 0 {
|
|
t.Fatalf("UniqueGiftChatThemes(0) = themes %d chats %d users %d, want empty vectors",
|
|
len(got.Themes), len(got.Chats), len(got.Users))
|
|
}
|
|
if _, ok := UniqueGiftChatThemes(got.Hash).(*tg.AccountChatThemesNotModified); !ok {
|
|
t.Fatalf("UniqueGiftChatThemes(hash) = %#v, want notModified", UniqueGiftChatThemes(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestWallPapersUsesDefaultFileCatalog(t *testing.T) {
|
|
got, ok := WallPapers(0).(*tg.AccountWallPapers)
|
|
if !ok {
|
|
t.Fatalf("WallPapers(0) = %T, want modified list", got)
|
|
}
|
|
if got.Hash == 0 {
|
|
t.Fatal("WallPapers(0).Hash = 0, want stable cache hash")
|
|
}
|
|
if len(got.Wallpapers) == 0 {
|
|
t.Fatal("WallPapers(0).Wallpapers is empty")
|
|
}
|
|
wallpaper, ok := got.Wallpapers[0].(*tg.WallPaper)
|
|
if !ok {
|
|
t.Fatalf("WallPapers(0).Wallpapers[0] = %T, want *tg.WallPaper", got.Wallpapers[0])
|
|
}
|
|
if wallpaper.ID == 0 || wallpaper.AccessHash == 0 || wallpaper.Slug == "" {
|
|
t.Fatalf("wallpaper identity = id %d hash %d slug %q, want Default ids", wallpaper.ID, wallpaper.AccessHash, wallpaper.Slug)
|
|
}
|
|
doc, ok := wallpaper.Document.(*tg.Document)
|
|
if !ok {
|
|
t.Fatalf("wallpaper document = %T, want *tg.Document", wallpaper.Document)
|
|
}
|
|
if doc.ID == 0 || doc.AccessHash == 0 || doc.Size == 0 || doc.MimeType == "" || doc.DCID != appearanceSeedDCID {
|
|
t.Fatalf("wallpaper document = id %d hash %d size %d mime %q dc %d, want downloadable Default document",
|
|
doc.ID, doc.AccessHash, doc.Size, doc.MimeType, doc.DCID)
|
|
}
|
|
if len(doc.Thumbs) == 0 {
|
|
t.Fatal("wallpaper document has no thumbnails")
|
|
}
|
|
if _, ok := doc.Thumbs[0].(*tg.PhotoSize); !ok {
|
|
t.Fatalf("wallpaper thumb = %T, want *tg.PhotoSize", doc.Thumbs[0])
|
|
}
|
|
if _, ok := WallPapers(got.Hash).(*tg.AccountWallPapersNotModified); !ok {
|
|
t.Fatalf("WallPapers(hash) = %#v, want notModified", WallPapers(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestLookupWallPaperByIDAndSlug(t *testing.T) {
|
|
catalog := WallPapers(0).(*tg.AccountWallPapers)
|
|
first := catalog.Wallpapers[0].(*tg.WallPaper)
|
|
byID, ok := LookupWallPaper(&tg.InputWallPaper{ID: first.ID, AccessHash: first.AccessHash})
|
|
if !ok {
|
|
t.Fatal("LookupWallPaper(inputWallPaper) = false, want true")
|
|
}
|
|
if got := byID.(*tg.WallPaper).Slug; got != first.Slug {
|
|
t.Fatalf("LookupWallPaper(inputWallPaper).Slug = %q, want %q", got, first.Slug)
|
|
}
|
|
bySlug, ok := LookupWallPaper(&tg.InputWallPaperSlug{Slug: first.Slug})
|
|
if !ok {
|
|
t.Fatal("LookupWallPaper(inputWallPaperSlug) = false, want true")
|
|
}
|
|
if got := bySlug.(*tg.WallPaper).ID; got != first.ID {
|
|
t.Fatalf("LookupWallPaper(inputWallPaperSlug).ID = %d, want %d", got, first.ID)
|
|
}
|
|
if _, ok := LookupWallPaper(&tg.InputWallPaper{ID: first.ID, AccessHash: first.AccessHash + 1}); ok {
|
|
t.Fatal("LookupWallPaper(wrong access hash) = true, want false")
|
|
}
|
|
multi, ok := LookupWallPapers([]tg.InputWallPaperClass{
|
|
&tg.InputWallPaper{ID: first.ID, AccessHash: first.AccessHash},
|
|
&tg.InputWallPaperSlug{Slug: catalog.Wallpapers[1].(*tg.WallPaper).Slug},
|
|
})
|
|
if !ok || len(multi) != 2 {
|
|
t.Fatalf("LookupWallPapers = len %d ok %v, want 2 true", len(multi), ok)
|
|
}
|
|
}
|
|
|
|
func TestDefaultThemeWallpaperReferencesResolve(t *testing.T) {
|
|
themes := DefaultThemeList()
|
|
var checked int
|
|
for _, theme := range themes {
|
|
settings, ok := theme.GetSettings()
|
|
if !ok {
|
|
continue
|
|
}
|
|
for i, setting := range settings {
|
|
wallpaperClass, ok := setting.GetWallpaper()
|
|
if !ok {
|
|
continue
|
|
}
|
|
wallpaper, ok := wallpaperClass.(*tg.WallPaper)
|
|
if !ok {
|
|
continue
|
|
}
|
|
checked++
|
|
byID, ok := LookupWallPaper(&tg.InputWallPaper{
|
|
ID: wallpaper.ID,
|
|
AccessHash: wallpaper.AccessHash,
|
|
})
|
|
if !ok {
|
|
t.Fatalf("theme %d settings[%d] wallpaper id %d was not resolvable", theme.ID, i, wallpaper.ID)
|
|
}
|
|
gotByID, ok := byID.(*tg.WallPaper)
|
|
if !ok || gotByID.ID != wallpaper.ID || gotByID.AccessHash != wallpaper.AccessHash {
|
|
t.Fatalf("theme %d settings[%d] wallpaper id lookup = %#v", theme.ID, i, byID)
|
|
}
|
|
bySlug, ok := LookupWallPaper(&tg.InputWallPaperSlug{Slug: wallpaper.Slug})
|
|
if !ok {
|
|
t.Fatalf("theme %d settings[%d] wallpaper slug %q was not resolvable", theme.ID, i, wallpaper.Slug)
|
|
}
|
|
gotBySlug, ok := bySlug.(*tg.WallPaper)
|
|
if !ok || gotBySlug.Slug != wallpaper.Slug {
|
|
t.Fatalf("theme %d settings[%d] wallpaper slug lookup = %#v", theme.ID, i, bySlug)
|
|
}
|
|
}
|
|
byThemeSlug, ok := LookupWallPaper(&tg.InputWallPaperSlug{Slug: theme.Slug})
|
|
if !ok {
|
|
t.Fatalf("theme %d fallback wallpaper alias %q was not resolvable", theme.ID, theme.Slug)
|
|
}
|
|
aliasWallpaper, ok := byThemeSlug.(*tg.WallPaper)
|
|
firstWallpaperClass, firstOK := settings[0].GetWallpaper()
|
|
firstWallpaper, firstFile := firstWallpaperClass.(*tg.WallPaper)
|
|
if !ok || !firstOK || !firstFile || aliasWallpaper.ID != firstWallpaper.ID || aliasWallpaper.Slug != firstWallpaper.Slug {
|
|
t.Fatalf("theme %d fallback alias = %#v, want settings[0] wallpaper %#v", theme.ID, byThemeSlug, firstWallpaperClass)
|
|
}
|
|
}
|
|
if checked == 0 {
|
|
t.Fatal("default themes exposed no file wallpapers")
|
|
}
|
|
}
|
|
|
|
func TestChatThemeWallpaperAliasRejectsAmbiguousSettings(t *testing.T) {
|
|
themes := []appearance.ChatTheme{{
|
|
Slug: "theme-alias",
|
|
Settings: []appearance.ThemeSettings{
|
|
{Wallpaper: appearance.Wallpaper{ID: 1, AccessHash: 11, Slug: "wallpaper-one"}},
|
|
{Wallpaper: appearance.Wallpaper{ID: 2, AccessHash: 22, Slug: "wallpaper-two"}},
|
|
},
|
|
}}
|
|
if _, ok := lookupChatThemeWallpaperAlias(themes, "theme-alias"); ok {
|
|
t.Fatal("ambiguous theme wallpaper alias was accepted")
|
|
}
|
|
if _, ok := lookupChatThemeWallpaperAlias(themes, "unknown"); ok {
|
|
t.Fatal("unknown theme wallpaper alias was accepted")
|
|
}
|
|
}
|
|
|
|
func TestStarsRevenueStatsIsZeroBalanceCompatStub(t *testing.T) {
|
|
got := StarsRevenueStats(false)
|
|
if got == nil {
|
|
t.Fatal("StarsRevenueStats(false) = nil")
|
|
}
|
|
if _, ok := got.RevenueGraph.(*tg.StatsGraphError); !ok {
|
|
t.Fatalf("RevenueGraph = %T, want *tg.StatsGraphError", got.RevenueGraph)
|
|
}
|
|
if got.Status.WithdrawalEnabled {
|
|
t.Fatal("WithdrawalEnabled = true, want false")
|
|
}
|
|
if _, ok := got.Status.CurrentBalance.(*tg.StarsAmount); !ok {
|
|
t.Fatalf("CurrentBalance = %T, want *tg.StarsAmount", got.Status.CurrentBalance)
|
|
}
|
|
|
|
ton := StarsRevenueStats(true)
|
|
if _, ok := ton.Status.CurrentBalance.(*tg.StarsTonAmount); !ok {
|
|
t.Fatalf("TON CurrentBalance = %T, want *tg.StarsTonAmount", ton.Status.CurrentBalance)
|
|
}
|
|
}
|
|
|
|
func TestCollectibleEmojiStatusesIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := CollectibleEmojiStatuses().(*tg.AccountEmojiStatuses)
|
|
if !ok {
|
|
t.Fatalf("CollectibleEmojiStatuses() = %T, want empty modified list", got)
|
|
}
|
|
if got.Hash != 0 {
|
|
t.Fatalf("CollectibleEmojiStatuses().Hash = %d, want 0", got.Hash)
|
|
}
|
|
if len(got.Statuses) != 0 {
|
|
t.Fatalf("CollectibleEmojiStatuses().Statuses length = %d, want 0", len(got.Statuses))
|
|
}
|
|
}
|
|
|
|
func TestDefaultGroupPhotoEmojisIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := DefaultGroupPhotoEmojis().(*tg.EmojiList)
|
|
if !ok {
|
|
t.Fatalf("DefaultGroupPhotoEmojis() = %T, want empty modified list", got)
|
|
}
|
|
if got.Hash != 0 {
|
|
t.Fatalf("DefaultGroupPhotoEmojis().Hash = %d, want 0", got.Hash)
|
|
}
|
|
if len(got.DocumentID) != 0 {
|
|
t.Fatalf("DefaultGroupPhotoEmojis().DocumentID length = %d, want 0", len(got.DocumentID))
|
|
}
|
|
}
|
|
|
|
func TestEmojiProfilePhotoGroupsIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := EmojiProfilePhotoGroups().(*tg.MessagesEmojiGroups)
|
|
if !ok {
|
|
t.Fatalf("EmojiProfilePhotoGroups() = %T, want empty modified list", got)
|
|
}
|
|
if got.Hash != 0 {
|
|
t.Fatalf("EmojiProfilePhotoGroups().Hash = %d, want 0", got.Hash)
|
|
}
|
|
if len(got.Groups) != 0 {
|
|
t.Fatalf("EmojiProfilePhotoGroups().Groups length = %d, want 0", len(got.Groups))
|
|
}
|
|
}
|
|
|
|
func TestEmojiStatusGroupsIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := EmojiStatusGroups().(*tg.MessagesEmojiGroups)
|
|
if !ok {
|
|
t.Fatalf("EmojiStatusGroups() = %T, want empty modified list", got)
|
|
}
|
|
if got.Hash != 0 {
|
|
t.Fatalf("EmojiStatusGroups().Hash = %d, want 0", got.Hash)
|
|
}
|
|
if len(got.Groups) != 0 {
|
|
t.Fatalf("EmojiStatusGroups().Groups length = %d, want 0", len(got.Groups))
|
|
}
|
|
}
|
|
|
|
func TestQuickRepliesIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := QuickReplies().(*tg.MessagesQuickReplies)
|
|
if !ok {
|
|
t.Fatalf("QuickReplies() = %T, want empty modified list", got)
|
|
}
|
|
if len(got.QuickReplies) != 0 || len(got.Messages) != 0 || len(got.Chats) != 0 || len(got.Users) != 0 {
|
|
t.Fatalf("QuickReplies() = shortcuts %d messages %d chats %d users %d, want empty vectors",
|
|
len(got.QuickReplies), len(got.Messages), len(got.Chats), len(got.Users))
|
|
}
|
|
}
|
|
|
|
func TestPeerColorsAreNonEmptyHashableAccentSets(t *testing.T) {
|
|
got, ok := PeerColors(0).(*tg.HelpPeerColors)
|
|
if !ok {
|
|
t.Fatalf("PeerColors(0) = %T, want modified colors", got)
|
|
}
|
|
if got.Hash == 0 || len(got.Colors) == 0 {
|
|
t.Fatalf("PeerColors(0) = hash %d colors %d, want non-empty stable list", got.Hash, len(got.Colors))
|
|
}
|
|
if len(got.Colors) != 21 {
|
|
t.Fatalf("PeerColors(0).Colors length = %d, want Default palette count 21", len(got.Colors))
|
|
}
|
|
withExplicitColors := 0
|
|
for i, option := range got.Colors {
|
|
if !IsPeerColorID(option.ColorID) {
|
|
t.Fatalf("PeerColors()[%d].ColorID = %d, want supported id", i, option.ColorID)
|
|
}
|
|
colors, ok := option.GetColors()
|
|
if !ok {
|
|
if option.ColorID > 6 {
|
|
t.Fatalf("PeerColors()[%d].Colors missing for non-default id %d", i, option.ColorID)
|
|
}
|
|
continue
|
|
}
|
|
if _, ok := colors.(*tg.HelpPeerColorSet); !ok {
|
|
t.Fatalf("PeerColors()[%d].Colors = %T, want *tg.HelpPeerColorSet", i, colors)
|
|
}
|
|
withExplicitColors++
|
|
}
|
|
if withExplicitColors == 0 {
|
|
t.Fatal("PeerColors() has no explicit Default color sets")
|
|
}
|
|
if _, ok := PeerColors(got.Hash).(*tg.HelpPeerColorsNotModified); !ok {
|
|
t.Fatalf("PeerColors(hash) = %#v, want notModified", PeerColors(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestPeerProfileColorsAreNonEmptyHashableProfileSets(t *testing.T) {
|
|
got, ok := PeerProfileColors(0).(*tg.HelpPeerColors)
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors(0) = %T, want modified colors", got)
|
|
}
|
|
if got.Hash == 0 || len(got.Colors) == 0 {
|
|
t.Fatalf("PeerProfileColors(0) = hash %d colors %d, want non-empty stable list", got.Hash, len(got.Colors))
|
|
}
|
|
if len(got.Colors) != 16 {
|
|
t.Fatalf("PeerProfileColors(0).Colors length = %d, want Default profile palette count 16", len(got.Colors))
|
|
}
|
|
for i, option := range got.Colors {
|
|
if !IsPeerProfileColorID(option.ColorID) {
|
|
t.Fatalf("PeerProfileColors()[%d].ColorID = %d, want supported id", i, option.ColorID)
|
|
}
|
|
groupMin, ok := option.GetGroupMinLevel()
|
|
if !ok || groupMin <= 0 || groupMin > maxPeerColorBoostLevel {
|
|
t.Fatalf("PeerProfileColors()[%d].group_min_level = %d ok %v, want bounded positive level", i, groupMin, ok)
|
|
}
|
|
if channelMin, ok := option.GetChannelMinLevel(); ok && (channelMin <= 0 || channelMin > maxPeerColorBoostLevel) {
|
|
t.Fatalf("PeerProfileColors()[%d].channel_min_level = %d, want bounded positive level", i, channelMin)
|
|
}
|
|
colors, ok := option.GetColors()
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors()[%d].Colors missing", i)
|
|
}
|
|
profile, ok := colors.(*tg.HelpPeerColorProfileSet)
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors()[%d].Colors = %T, want *tg.HelpPeerColorProfileSet", i, colors)
|
|
}
|
|
if len(profile.PaletteColors) == 0 || len(profile.BgColors) == 0 || len(profile.StoryColors) != 2 {
|
|
t.Fatalf("PeerProfileColors()[%d] = palette %d bg %d story %d, want usable profile palette",
|
|
i, len(profile.PaletteColors), len(profile.BgColors), len(profile.StoryColors))
|
|
}
|
|
}
|
|
if _, ok := PeerProfileColors(got.Hash).(*tg.HelpPeerColorsNotModified); !ok {
|
|
t.Fatalf("PeerProfileColors(hash) = %#v, want notModified", PeerProfileColors(got.Hash))
|
|
}
|
|
}
|
|
|
|
func TestPeerProfileColorsKeepTDesktopBoostFeatureLevelsBounded(t *testing.T) {
|
|
got, ok := PeerProfileColors(0).(*tg.HelpPeerColors)
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors(0) = %T, want modified colors", got)
|
|
}
|
|
levels := make([]int, 0, len(got.Colors))
|
|
lowestNonZeroLevel := math.MaxInt
|
|
for _, option := range got.Colors {
|
|
level, ok := option.GetGroupMinLevel()
|
|
if !ok {
|
|
level = 0
|
|
}
|
|
levels = append(levels, level)
|
|
if level != 0 && level < lowestNonZeroLevel {
|
|
lowestNonZeroLevel = level
|
|
}
|
|
}
|
|
if lowestNonZeroLevel == math.MaxInt {
|
|
t.Fatal("profile color group levels are all zero; TDesktop would aggregate them at MaxInt in BoostBox")
|
|
}
|
|
maxFeatureLevel := 0
|
|
for _, level := range levels {
|
|
if level < lowestNonZeroLevel {
|
|
level = lowestNonZeroLevel
|
|
}
|
|
if level > maxFeatureLevel {
|
|
maxFeatureLevel = level
|
|
}
|
|
}
|
|
if maxFeatureLevel <= 0 || maxFeatureLevel > maxPeerColorBoostLevel {
|
|
t.Fatalf("TDesktop profile feature max level = %d, want 1..%d", maxFeatureLevel, maxPeerColorBoostLevel)
|
|
}
|
|
}
|
|
|
|
func TestPeerProfileColorsReturnsIndependentOptions(t *testing.T) {
|
|
first, ok := PeerProfileColors(0).(*tg.HelpPeerColors)
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors(0) first = %T, want modified colors", first)
|
|
}
|
|
second, ok := PeerProfileColors(0).(*tg.HelpPeerColors)
|
|
if !ok {
|
|
t.Fatalf("PeerProfileColors(0) second = %T, want modified colors", second)
|
|
}
|
|
if len(first.Colors) == 0 || len(second.Colors) == 0 {
|
|
t.Fatal("PeerProfileColors returned empty colors")
|
|
}
|
|
first.Colors[0].SetGroupMinLevel(maxPeerColorBoostLevel + 1)
|
|
if groupMin, ok := second.Colors[0].GetGroupMinLevel(); !ok || groupMin > maxPeerColorBoostLevel {
|
|
t.Fatalf("second PeerProfileColors group_min_level = %d ok %v, want independent bounded copy", groupMin, ok)
|
|
}
|
|
|
|
firstSet, ok := first.Colors[0].Colors.(*tg.HelpPeerColorProfileSet)
|
|
if !ok || len(firstSet.PaletteColors) == 0 {
|
|
t.Fatalf("first profile colors = %T %+v, want profile set with palette", first.Colors[0].Colors, first.Colors[0].Colors)
|
|
}
|
|
secondSet, ok := second.Colors[0].Colors.(*tg.HelpPeerColorProfileSet)
|
|
if !ok || len(secondSet.PaletteColors) == 0 {
|
|
t.Fatalf("second profile colors = %T %+v, want profile set with palette", second.Colors[0].Colors, second.Colors[0].Colors)
|
|
}
|
|
original := secondSet.PaletteColors[0]
|
|
firstSet.PaletteColors[0] = original + 1
|
|
if secondSet.PaletteColors[0] != original {
|
|
t.Fatalf("second profile palette mutated through first response: got %d want %d", secondSet.PaletteColors[0], original)
|
|
}
|
|
}
|
|
|
|
func TestStoryAlbumsIsEmptyModifiedList(t *testing.T) {
|
|
got, ok := StoryAlbums().(*tg.StoriesAlbums)
|
|
if !ok {
|
|
t.Fatalf("StoryAlbums() = %T, want empty modified list", got)
|
|
}
|
|
if got.Hash != 0 {
|
|
t.Fatalf("StoryAlbums().Hash = %d, want 0", got.Hash)
|
|
}
|
|
if len(got.Albums) != 0 {
|
|
t.Fatalf("StoryAlbums().Albums length = %d, want 0", len(got.Albums))
|
|
}
|
|
}
|
|
|
|
func TestStickerSetReturnsEmptyModifiedSetForColdRequest(t *testing.T) {
|
|
got, ok := StickerSet(&tg.MessagesGetStickerSetRequest{
|
|
Stickerset: &tg.InputStickerSetEmojiGenericAnimations{},
|
|
Hash: 0,
|
|
}).(*tg.MessagesStickerSet)
|
|
if !ok {
|
|
t.Fatalf("StickerSet(hash=0) = %T, want modified empty set", got)
|
|
}
|
|
if got.Set.Hash == 0 {
|
|
t.Fatal("StickerSet(hash=0).Set.Hash = 0, want stable cache hash")
|
|
}
|
|
if got.Set.ShortName != "EmojiGenericAnimations" {
|
|
t.Fatalf("StickerSet(hash=0).Set.ShortName = %q, want EmojiGenericAnimations", got.Set.ShortName)
|
|
}
|
|
if len(got.Packs) != 0 || len(got.Keywords) != 0 || len(got.Documents) != 0 {
|
|
t.Fatalf("StickerSet(hash=0) = packs %d keywords %d documents %d, want empty vectors", len(got.Packs), len(got.Keywords), len(got.Documents))
|
|
}
|
|
if _, ok := StickerSet(&tg.MessagesGetStickerSetRequest{
|
|
Stickerset: &tg.InputStickerSetEmojiGenericAnimations{},
|
|
Hash: got.Set.Hash,
|
|
}).(*tg.MessagesStickerSetNotModified); !ok {
|
|
t.Fatalf("StickerSet(hash) = %#v, want notModified", StickerSet(&tg.MessagesGetStickerSetRequest{
|
|
Stickerset: &tg.InputStickerSetEmojiGenericAnimations{},
|
|
Hash: got.Set.Hash,
|
|
}))
|
|
}
|
|
}
|