package cp import ( "context" "testing" "hyapp/pkg/appcode" cpdomain "hyapp/services/user-service/internal/domain/cp" ) func TestRefreshIntimacyLeaderboardHydratesAvatarFrames(t *testing.T) { repo := &fakeLeaderboardRepo{ entries: []cpdomain.IntimacyLeaderboardEntry{{ RelationshipID: "rank_cp_1", RelationType: cpdomain.RelationTypeCP, IntimacyValue: 300, Level: 2, UserA: cpdomain.IntimacyLeaderboardUser{UserID: 7101, DisplayUserID: "7101", Username: "A", Avatar: "a.png"}, UserB: cpdomain.IntimacyLeaderboardUser{UserID: 7102, DisplayUserID: "7102", Username: "B", Avatar: "b.png"}, }}, } store := &fakeLeaderboardStore{} frames := &fakeAvatarFrameReader{frames: map[int64]cpdomain.AvatarFrameSnapshot{ 7101: {ResourceID: 9101, ResourceCode: "frame_gold", Name: "Gold", AssetURL: "gold.png"}, 7102: {ResourceID: 9102, ResourceCode: "frame_blue", Name: "Blue", AssetURL: "blue.png"}, }} svc := New(repo, WithIntimacyLeaderboardStore(store), WithAvatarFrameReader(frames)) processed, err := svc.RefreshIntimacyLeaderboard(appcode.WithContext(context.Background(), appcode.Default), 100) if err != nil { t.Fatalf("refresh leaderboard failed: %v", err) } if processed != 1 || len(store.entries) != 1 { t.Fatalf("processed/store mismatch: processed=%d entries=%+v", processed, store.entries) } entry := store.entries[0] if entry.UserA.AvatarFrame == nil || entry.UserA.AvatarFrame.ResourceID != 9101 || entry.UserB.AvatarFrame == nil || entry.UserB.AvatarFrame.ResourceCode != "frame_blue" { t.Fatalf("avatar frames must be hydrated before zset replace: %+v", entry) } if len(frames.userIDs) != 2 || frames.userIDs[0] != 7101 || frames.userIDs[1] != 7102 { t.Fatalf("avatar frame reader should receive both users once: %+v", frames.userIDs) } } type fakeLeaderboardRepo struct { entries []cpdomain.IntimacyLeaderboardEntry } func (r *fakeLeaderboardRepo) ListApplications(context.Context, int64, string, string, int32, int32, int64) ([]cpdomain.Application, int64, error) { return nil, 0, nil } func (r *fakeLeaderboardRepo) AcceptApplication(context.Context, int64, string, int64) (cpdomain.Application, cpdomain.Relationship, error) { return cpdomain.Application{}, cpdomain.Relationship{}, nil } func (r *fakeLeaderboardRepo) RejectApplication(context.Context, int64, string, string, int64) (cpdomain.Application, error) { return cpdomain.Application{}, nil } func (r *fakeLeaderboardRepo) ListRelationships(context.Context, int64, string, int32, int32) ([]cpdomain.Relationship, int64, error) { return nil, 0, nil } func (r *fakeLeaderboardRepo) PrepareBreakRelationship(context.Context, int64, string, string, int64) (cpdomain.RelationshipBreakup, cpdomain.Relationship, error) { return cpdomain.RelationshipBreakup{}, cpdomain.Relationship{}, nil } func (r *fakeLeaderboardRepo) ConfirmBreakRelationship(context.Context, int64, string, string, string, int64, int64, int64) (cpdomain.RelationshipBreakup, cpdomain.Relationship, error) { return cpdomain.RelationshipBreakup{}, cpdomain.Relationship{}, nil } func (r *fakeLeaderboardRepo) CancelBreakRelationship(context.Context, int64, string, string, string, int64) (cpdomain.RelationshipBreakup, error) { return cpdomain.RelationshipBreakup{}, nil } func (r *fakeLeaderboardRepo) ConsumeGiftEvent(context.Context, cpdomain.GiftEvent, int64) (cpdomain.ConsumeResult, error) { return cpdomain.ConsumeResult{}, nil } func (r *fakeLeaderboardRepo) ListActiveIntimacyLeaderboardEntries(context.Context, int) ([]cpdomain.IntimacyLeaderboardEntry, error) { return r.entries, nil } func (r *fakeLeaderboardRepo) ListWeeklyRankEntries(context.Context, string, int64, int64, int) ([]cpdomain.WeeklyRankEntry, error) { return nil, nil } type fakeLeaderboardStore struct { entries []cpdomain.IntimacyLeaderboardEntry } func (s *fakeLeaderboardStore) ReplaceIntimacyLeaderboard(_ context.Context, _ string, entries []cpdomain.IntimacyLeaderboardEntry) error { s.entries = append([]cpdomain.IntimacyLeaderboardEntry(nil), entries...) return nil } func (s *fakeLeaderboardStore) ListIntimacyLeaderboard(_ context.Context, _ string, _ string, page int32, pageSize int32, nowMs int64) (cpdomain.IntimacyLeaderboardPage, error) { return cpdomain.IntimacyLeaderboardPage{Items: s.entries, Total: int64(len(s.entries)), Page: page, PageSize: pageSize, ServerTimeMS: nowMs}, nil } type fakeAvatarFrameReader struct { frames map[int64]cpdomain.AvatarFrameSnapshot userIDs []int64 } func (r *fakeAvatarFrameReader) BatchGetAvatarFrames(_ context.Context, _ string, userIDs []int64) (map[int64]cpdomain.AvatarFrameSnapshot, error) { r.userIDs = append([]int64(nil), userIDs...) return r.frames, nil }