eq2go/internal/achievements/achievements_test.go

287 lines
7.9 KiB
Go

package achievements
import (
"sync"
"testing"
"eq2emu/internal/database"
)
// TestSimpleAchievement tests the basic new Achievement functionality
func TestSimpleAchievement(t *testing.T) {
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Test creating a new achievement
achievement := New(db)
if achievement == nil {
t.Fatal("New returned nil")
}
if !achievement.IsNew() {
t.Error("New achievement should be marked as new")
}
// Test setting values
achievement.AchievementID = 1001
achievement.Title = "Test Achievement"
achievement.Category = "Testing"
if achievement.GetID() != 1001 {
t.Errorf("Expected GetID() to return 1001, got %d", achievement.GetID())
}
// Test adding requirements and rewards
achievement.AddRequirement("kill_monsters", 10)
achievement.AddReward("experience:1000")
if len(achievement.Requirements) != 1 {
t.Errorf("Expected 1 requirement, got %d", len(achievement.Requirements))
}
if len(achievement.Rewards) != 1 {
t.Errorf("Expected 1 reward, got %d", len(achievement.Rewards))
}
// Test Clone
clone := achievement.Clone()
if clone == nil {
t.Fatal("Clone returned nil")
}
if clone.AchievementID != achievement.AchievementID {
t.Errorf("Expected clone ID %d, got %d", achievement.AchievementID, clone.AchievementID)
}
if clone.Title != achievement.Title {
t.Errorf("Expected clone title %s, got %s", achievement.Title, clone.Title)
}
}
// TestMasterList tests the bespoke master list implementation
func TestMasterList(t *testing.T) {
masterList := NewMasterList()
if masterList == nil {
t.Fatal("NewMasterList returned nil")
}
if masterList.Size() != 0 {
t.Errorf("Expected size 0, got %d", masterList.Size())
}
// Create test database
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Create achievements for testing
achievement1 := New(db)
achievement1.AchievementID = 1001
achievement1.Title = "Test Achievement 1"
achievement1.Category = "Testing"
achievement1.Expansion = "Classic"
achievement2 := New(db)
achievement2.AchievementID = 1002
achievement2.Title = "Test Achievement 2"
achievement2.Category = "Combat"
achievement2.Expansion = "Classic"
achievement3 := New(db)
achievement3.AchievementID = 1003
achievement3.Title = "Test Achievement 3"
achievement3.Category = "Testing"
achievement3.Expansion = "Expansion1"
// Test adding
if !masterList.AddAchievement(achievement1) {
t.Error("Should successfully add achievement1")
}
if !masterList.AddAchievement(achievement2) {
t.Error("Should successfully add achievement2")
}
if !masterList.AddAchievement(achievement3) {
t.Error("Should successfully add achievement3")
}
if masterList.Size() != 3 {
t.Errorf("Expected size 3, got %d", masterList.Size())
}
// Test duplicate add (should fail)
if masterList.AddAchievement(achievement1) {
t.Error("Should not add duplicate achievement")
}
// Test retrieving
retrieved := masterList.GetAchievement(1001)
if retrieved == nil {
t.Error("Should retrieve added achievement")
}
if retrieved.Title != "Test Achievement 1" {
t.Errorf("Expected title 'Test Achievement 1', got '%s'", retrieved.Title)
}
// Test category filtering
testingAchievements := masterList.GetAchievementsByCategory("Testing")
if len(testingAchievements) != 2 {
t.Errorf("Expected 2 achievements in Testing category, got %d", len(testingAchievements))
}
combatAchievements := masterList.GetAchievementsByCategory("Combat")
if len(combatAchievements) != 1 {
t.Errorf("Expected 1 achievement in Combat category, got %d", len(combatAchievements))
}
// Test expansion filtering
classicAchievements := masterList.GetAchievementsByExpansion("Classic")
if len(classicAchievements) != 2 {
t.Errorf("Expected 2 achievements in Classic expansion, got %d", len(classicAchievements))
}
expansion1Achievements := masterList.GetAchievementsByExpansion("Expansion1")
if len(expansion1Achievements) != 1 {
t.Errorf("Expected 1 achievement in Expansion1, got %d", len(expansion1Achievements))
}
// Test combined filtering
combined := masterList.GetAchievementsByCategoryAndExpansion("Testing", "Classic")
if len(combined) != 1 {
t.Errorf("Expected 1 achievement matching Testing+Classic, got %d", len(combined))
}
// Test metadata caching
categories := masterList.GetCategories()
if len(categories) != 2 {
t.Errorf("Expected 2 unique categories, got %d", len(categories))
}
expansions := masterList.GetExpansions()
if len(expansions) != 2 {
t.Errorf("Expected 2 unique expansions, got %d", len(expansions))
}
// Test clone
clone := masterList.GetAchievementClone(1001)
if clone == nil {
t.Error("Should return cloned achievement")
}
if clone.Title != "Test Achievement 1" {
t.Errorf("Expected cloned title 'Test Achievement 1', got '%s'", clone.Title)
}
// Test GetAllAchievements
allAchievements := masterList.GetAllAchievements()
if len(allAchievements) != 3 {
t.Errorf("Expected 3 achievements in GetAll, got %d", len(allAchievements))
}
// Test update
updatedAchievement := New(db)
updatedAchievement.AchievementID = 1001
updatedAchievement.Title = "Updated Achievement"
updatedAchievement.Category = "Updated"
updatedAchievement.Expansion = "Updated"
if err := masterList.UpdateAchievement(updatedAchievement); err != nil {
t.Errorf("Update should succeed: %v", err)
}
// Verify update worked
retrievedUpdated := masterList.GetAchievement(1001)
if retrievedUpdated.Title != "Updated Achievement" {
t.Errorf("Expected updated title 'Updated Achievement', got '%s'", retrievedUpdated.Title)
}
// Verify category index updated
updatedCategoryAchievements := masterList.GetAchievementsByCategory("Updated")
if len(updatedCategoryAchievements) != 1 {
t.Errorf("Expected 1 achievement in Updated category, got %d", len(updatedCategoryAchievements))
}
// Test removal
if !masterList.RemoveAchievement(1001) {
t.Error("Should successfully remove achievement")
}
if masterList.Size() != 2 {
t.Errorf("Expected size 2 after removal, got %d", masterList.Size())
}
// Test clear
masterList.Clear()
if masterList.Size() != 0 {
t.Errorf("Expected size 0 after clear, got %d", masterList.Size())
}
}
// TestMasterListConcurrency tests thread safety of the master list
func TestMasterListConcurrency(t *testing.T) {
masterList := NewMasterList()
// Create test database
db, err := database.NewSQLite("file::memory:?mode=memory&cache=shared")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
const numWorkers = 10
const achievementsPerWorker = 100
var wg sync.WaitGroup
// Concurrently add achievements
wg.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
go func(workerID int) {
defer wg.Done()
for j := 0; j < achievementsPerWorker; j++ {
achievement := New(db)
achievement.AchievementID = uint32(workerID*achievementsPerWorker + j + 1)
achievement.Title = "Concurrent Test"
achievement.Category = "Concurrency"
achievement.Expansion = "Test"
masterList.AddAchievement(achievement)
}
}(i)
}
// Concurrently read achievements
wg.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
go func() {
defer wg.Done()
for j := 0; j < achievementsPerWorker; j++ {
// Random reads
_ = masterList.GetAchievement(uint32(j + 1))
_ = masterList.GetAchievementsByCategory("Concurrency")
_ = masterList.GetAchievementsByExpansion("Test")
_ = masterList.Size()
}
}()
}
wg.Wait()
// Verify final state
expectedSize := numWorkers * achievementsPerWorker
if masterList.Size() != expectedSize {
t.Errorf("Expected size %d, got %d", expectedSize, masterList.Size())
}
categories := masterList.GetCategories()
if len(categories) != 1 || categories[0] != "Concurrency" {
t.Errorf("Expected 1 category 'Concurrency', got %v", categories)
}
}