mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-28 02:23:37 +01:00
refactor(achievement): extract achievement logic into AchievementService
Move EnsureExists + GetAllScores + compute loop from handler into AchievementService.GetAll, and validation + ensure + increment into AchievementService.Increment. Handlers now delegate to the service layer for business logic while retaining protocol response building. GetAchData stays as a pure function in handlers_achievement.go per plan.
This commit is contained in:
169
server/channelserver/svc_achievement_test.go
Normal file
169
server/channelserver/svc_achievement_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func newTestAchievementService(repo AchievementRepo) *AchievementService {
|
||||
logger, _ := zap.NewDevelopment()
|
||||
return NewAchievementService(repo, logger)
|
||||
}
|
||||
|
||||
func TestAchievementService_GetAll(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
scores [33]int32
|
||||
scoresErr error
|
||||
wantErr bool
|
||||
wantPoints uint32
|
||||
}{
|
||||
{
|
||||
name: "all zeros",
|
||||
scores: [33]int32{},
|
||||
wantPoints: 0,
|
||||
},
|
||||
{
|
||||
name: "some scores",
|
||||
scores: [33]int32{5, 0, 20},
|
||||
wantPoints: 5 + 0 + 15, // id0: level1=5pts, id1: level0=0pts, id2: level1(5)+level2(10)=15pts (score=20, curve[0]={5,15,...}: 20-5=15, 15-15=0 → level2=15pts)
|
||||
},
|
||||
{
|
||||
name: "db error",
|
||||
scoresErr: errNotFound,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &mockAchievementRepo{
|
||||
scores: tt.scores,
|
||||
getScoresErr: tt.scoresErr,
|
||||
}
|
||||
svc := newTestAchievementService(mock)
|
||||
|
||||
summary, err := svc.GetAll(1)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Fatal("Expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if !mock.ensureCalled {
|
||||
t.Error("EnsureExists should have been called")
|
||||
}
|
||||
if summary.Points != tt.wantPoints {
|
||||
t.Errorf("Points = %d, want %d", summary.Points, tt.wantPoints)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAchievementService_GetAll_EnsureErrorNonFatal(t *testing.T) {
|
||||
mock := &mockAchievementRepo{
|
||||
ensureErr: errNotFound,
|
||||
scores: [33]int32{},
|
||||
}
|
||||
svc := newTestAchievementService(mock)
|
||||
|
||||
summary, err := svc.GetAll(1)
|
||||
if err != nil {
|
||||
t.Fatalf("EnsureExists error should not propagate: %v", err)
|
||||
}
|
||||
if summary == nil {
|
||||
t.Fatal("Summary should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAchievementService_GetAll_AchievementCount(t *testing.T) {
|
||||
mock := &mockAchievementRepo{scores: [33]int32{}}
|
||||
svc := newTestAchievementService(mock)
|
||||
|
||||
summary, err := svc.GetAll(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Verify all 33 entries are populated
|
||||
for id := uint8(0); id < 33; id++ {
|
||||
// At score 0, every achievement should be level 0
|
||||
if summary.Achievements[id].Level != 0 {
|
||||
t.Errorf("Achievement[%d].Level = %d, want 0", id, summary.Achievements[id].Level)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAchievementService_Increment(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
achievementID uint8
|
||||
incrementErr error
|
||||
wantErr bool
|
||||
wantEnsure bool
|
||||
wantIncID uint8
|
||||
}{
|
||||
{
|
||||
name: "valid ID",
|
||||
achievementID: 5,
|
||||
wantEnsure: true,
|
||||
wantIncID: 5,
|
||||
},
|
||||
{
|
||||
name: "boundary ID 0",
|
||||
achievementID: 0,
|
||||
wantEnsure: true,
|
||||
wantIncID: 0,
|
||||
},
|
||||
{
|
||||
name: "boundary ID 32",
|
||||
achievementID: 32,
|
||||
wantEnsure: true,
|
||||
wantIncID: 32,
|
||||
},
|
||||
{
|
||||
name: "out of range",
|
||||
achievementID: 33,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "repo error",
|
||||
achievementID: 5,
|
||||
incrementErr: errNotFound,
|
||||
wantErr: true,
|
||||
wantEnsure: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &mockAchievementRepo{
|
||||
incrementErr: tt.incrementErr,
|
||||
}
|
||||
svc := newTestAchievementService(mock)
|
||||
|
||||
err := svc.Increment(1, tt.achievementID)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Fatal("Expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if mock.ensureCalled != tt.wantEnsure {
|
||||
t.Errorf("EnsureExists called = %v, want %v", mock.ensureCalled, tt.wantEnsure)
|
||||
}
|
||||
if mock.incrementedID != tt.wantIncID {
|
||||
t.Errorf("IncrementScore ID = %d, want %d", mock.incrementedID, tt.wantIncID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user