2026-05-15 19:42:02 +08:00

189 lines
7.3 KiB
Go

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 TestOtherBadgesUsesTargetUser(t *testing.T) {
db := newUserBadgeTestDB(t)
now := time.Date(2026, 5, 15, 12, 0, 0, 0, time.UTC)
viewerID := int64(42)
targetID := int64(99)
seedBadgeConfig(t, db, 201, badgeSourceTypeActivity, "Viewer Badge", "VIEWER_BADGE", 1)
seedBadgeConfig(t, db, 202, badgeSourceTypeAchievement, "Target Badge", "TARGET_BADGE", 2)
for _, badgeID := range []int64{201, 202} {
if err := db.Create(&model.SysBadgePictureConfig{
ID: badgeID + 1000,
BadgeConfigID: badgeID,
SysOrigin: "LIKEI",
SelectURL: "https://cdn.example.com/" + formatID(badgeID) + ".png",
}).Error; err != nil {
t.Fatalf("create picture %d: %v", badgeID, err)
}
}
backpacks := []model.UserBadgeBackpack{
{ID: 3001, UserID: viewerID, BadgeID: 201, ExpireType: "TEMPORARY", ExpireTime: now.Add(2 * time.Hour), UseProps: true, UpdateTime: now},
{ID: 3002, UserID: targetID, BadgeID: 202, ExpireType: "TEMPORARY", ExpireTime: now.Add(2 * time.Hour), UseProps: true, UpdateTime: now.Add(time.Minute)},
}
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.Other(context.Background(), common.AuthUser{UserID: viewerID, SysOrigin: "LIKEI"}, targetID)
if err != nil {
t.Fatalf("Other() error = %v", err)
}
if resp.UserID != targetID {
t.Fatalf("UserID = %d, want target %d", resp.UserID, targetID)
}
if len(resp.ShortBadges) != 1 || resp.ShortBadges[0].BadgeID != "202" {
t.Fatalf("short badges = %#v, want target badge 202", resp.ShortBadges)
}
}
func TestOtherBadgesRejectsInvalidTargetUser(t *testing.T) {
service := NewService(newUserBadgeTestDB(t))
_, err := service.Other(context.Background(), common.AuthUser{UserID: 42, SysOrigin: "LIKEI"}, 0)
if err == nil {
t.Fatalf("Other() error = nil, want invalid target user")
}
appErr, ok := err.(*AppError)
if !ok || appErr.Code != "invalid_target_user_id" {
t.Fatalf("error = %#v, want invalid_target_user_id", 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)
}
}