package userbadge import ( "context" "testing" "time" "chatapp3-golang/internal/common" "chatapp3-golang/internal/model" "gorm.io/driver/sqlite" "gorm.io/gorm" ) func TestCurrentBadgesSplitLongAndShort(t *testing.T) { db := newUserBadgeTestDB(t) now := time.Date(2026, 5, 15, 12, 0, 0, 0, time.UTC) userID := int64(42) if err := db.Create(&model.UserVipState{ ID: 1, SysOrigin: "LIKEI", UserID: userID, Level: 2, LevelCode: "VIP2", DisplayName: "VIP 2", Status: statusActive, StartAt: now.Add(-time.Hour), ExpireAt: now.Add(24 * time.Hour), BadgeResourceID: 101, }).Error; err != nil { t.Fatalf("create vip state: %v", err) } seedBadgeConfig(t, db, 101, "ACTIVITY", "VIP Badge", "VIP_BADGE", 5) seedBadgeConfig(t, db, 102, badgeSourceTypeActivity, "Activity Badge", "ACTIVITY_BADGE", 3) seedBadgeConfig(t, db, 103, badgeSourceTypeAchievement, "Achievement Badge", "ACHIEVEMENT_BADGE", 7) seedBadgeConfig(t, db, 104, "ADMINISTRATOR", "Admin Badge", "ADMIN_BADGE", 0) seedBadgeConfig(t, db, 105, badgeSourceTypeActivity, "Expired Badge", "EXPIRED_BADGE", 0) seedBadgeConfig(t, db, 106, badgeSourceTypeActivity, "Unused Badge", "UNUSED_BADGE", 0) for _, badgeID := range []int64{101, 102, 103, 104, 105, 106} { if err := db.Create(&model.SysBadgePictureConfig{ ID: badgeID + 1000, BadgeConfigID: badgeID, SysOrigin: "LIKEI", SelectURL: "https://cdn.example.com/" + formatID(badgeID) + ".png", NotSelectURL: "https://cdn.example.com/" + formatID(badgeID) + "-off.png", }).Error; err != nil { t.Fatalf("create picture %d: %v", badgeID, err) } } backpacks := []model.UserBadgeBackpack{ {ID: 2001, UserID: userID, BadgeID: 101, ExpireType: "TEMPORARY", ExpireTime: now.Add(24 * time.Hour), UseProps: true, UpdateTime: now.Add(5 * time.Minute)}, {ID: 2002, UserID: userID, BadgeID: 102, ExpireType: "TEMPORARY", ExpireTime: now.Add(2 * time.Hour), UseProps: true, UpdateTime: now.Add(4 * time.Minute)}, {ID: 2003, UserID: userID, BadgeID: 103, ExpireType: expireTypePermanent, ExpireTime: now.Add(-24 * time.Hour), UseProps: true, UpdateTime: now.Add(3 * time.Minute)}, {ID: 2004, UserID: userID, BadgeID: 104, ExpireType: "TEMPORARY", ExpireTime: now.Add(2 * time.Hour), UseProps: true, UpdateTime: now.Add(2 * time.Minute)}, {ID: 2005, UserID: userID, BadgeID: 105, ExpireType: "TEMPORARY", ExpireTime: now.Add(-time.Minute), UseProps: true, UpdateTime: now.Add(time.Minute)}, {ID: 2006, UserID: userID, BadgeID: 106, ExpireType: "TEMPORARY", ExpireTime: now.Add(2 * time.Hour), UseProps: false, UpdateTime: now}, } if err := db.Create(&backpacks).Error; err != nil { t.Fatalf("create backpacks: %v", err) } service := NewService(db) service.now = func() time.Time { return now } resp, err := service.Current(context.Background(), common.AuthUser{UserID: userID, SysOrigin: "likei"}) if err != nil { t.Fatalf("Current() error = %v", err) } if resp.SysOrigin != "LIKEI" { t.Fatalf("SysOrigin = %q, want LIKEI", resp.SysOrigin) } if len(resp.LongBadges) != 1 { t.Fatalf("long badges len = %d, want 1: %#v", len(resp.LongBadges), resp.LongBadges) } if len(resp.ShortBadges) != 2 { t.Fatalf("short badges len = %d, want 2: %#v", len(resp.ShortBadges), resp.ShortBadges) } if len(resp.Badges) != 3 { t.Fatalf("badges len = %d, want 3", len(resp.Badges)) } long := resp.LongBadges[0] if long.Type != badgeDisplayTypeLong || long.SourceType != badgeSourceTypeVIP || long.BadgeID != "101" || long.LevelCode != "VIP2" { t.Fatalf("long badge = %#v", long) } if long.Name != "VIP Badge" || long.URL != "https://cdn.example.com/101.png" { t.Fatalf("long badge name/url = %q/%q", long.Name, long.URL) } if resp.ShortBadges[0].BadgeID != "102" || resp.ShortBadges[0].SourceType != badgeSourceTypeActivity { t.Fatalf("first short badge = %#v", resp.ShortBadges[0]) } if resp.ShortBadges[1].BadgeID != "103" || resp.ShortBadges[1].SourceType != badgeSourceTypeAchievement { t.Fatalf("second short badge = %#v", resp.ShortBadges[1]) } } func TestCurrentBadgesRejectsInvalidUser(t *testing.T) { service := NewService(newUserBadgeTestDB(t)) _, err := service.Current(context.Background(), common.AuthUser{SysOrigin: "LIKEI"}) if err == nil { t.Fatalf("Current() error = nil, want invalid user") } appErr, ok := err.(*AppError) if !ok || appErr.Code != "invalid_user" { t.Fatalf("error = %#v, want invalid_user", err) } } func newUserBadgeTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatalf("open sqlite: %v", err) } if err := db.AutoMigrate( &model.UserVipState{}, &model.UserBadgeBackpack{}, &model.SysBadgeConfig{}, &model.SysBadgePictureConfig{}, ); err != nil { t.Fatalf("migrate sqlite: %v", err) } return db } func seedBadgeConfig(t *testing.T, db *gorm.DB, id int64, sourceType string, name string, key string, level int) { t.Helper() if err := db.Create(&model.SysBadgeConfig{ ID: id, Type: sourceType, BadgeName: name, BadgeKey: key, BadgeLevel: level, Milestone: id * 10, Del: false, }).Error; err != nil { t.Fatalf("create badge config %d: %v", id, err) } }