eq2go/internal/collections/benchmark_test.go
2025-08-08 12:13:38 -05:00

456 lines
11 KiB
Go

package collections
import (
"fmt"
"testing"
"eq2emu/internal/database"
)
// Setup creates a master list with test data for benchmarking
func benchmarkSetup() *MasterList {
db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared")
masterList := NewMasterList()
// Add collections across different categories and levels
categories := []string{
"Heritage", "Treasured", "Legendary", "Fabled", "Mythical",
"Handcrafted", "Mastercrafted", "Rare", "Uncommon", "Common",
}
for i := 0; i < 100; i++ {
category := categories[i%len(categories)]
level := int8((i % 50) + 1) // Levels 1-50
collection := NewWithData(int32(i+1), fmt.Sprintf("Collection %d", i+1), category, level, db)
// Add collection items (some found, some not)
numItems := (i % 5) + 1 // 1-5 items per collection
for j := 0; j < numItems; j++ {
found := ItemNotFound
if (i+j)%3 == 0 { // About 1/3 of items are found
found = ItemFound
}
collection.CollectionItems = append(collection.CollectionItems, CollectionItem{
ItemID: int32((i+1)*1000 + j + 1),
Index: int8(j),
Found: int8(found),
})
}
// Add rewards
if i%4 == 0 {
collection.RewardCoin = int64((i + 1) * 100)
}
if i%5 == 0 {
collection.RewardXP = int64((i + 1) * 50)
}
if i%6 == 0 {
collection.RewardItems = append(collection.RewardItems, CollectionRewardItem{
ItemID: int32(i + 10000),
Quantity: 1,
})
}
if i%7 == 0 {
collection.SelectableRewardItems = append(collection.SelectableRewardItems, CollectionRewardItem{
ItemID: int32(i + 20000),
Quantity: 1,
})
}
// Some collections are completed
if i%10 == 0 {
collection.Completed = true
}
masterList.AddCollection(collection)
}
return masterList
}
func BenchmarkMasterList_AddCollection(b *testing.B) {
db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared")
defer db.Close()
masterList := NewMasterList()
b.ResetTimer()
for i := 0; i < b.N; i++ {
collection := NewWithData(int32(i+10000), fmt.Sprintf("Collection%d", i), "Heritage", 20, db)
collection.CollectionItems = []CollectionItem{
{ItemID: int32(i + 50000), Index: 0, Found: ItemNotFound},
}
masterList.AddCollection(collection)
}
}
func BenchmarkMasterList_GetCollection(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCollection(int32(i%100 + 1))
}
}
func BenchmarkMasterList_GetCollectionSafe(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCollectionSafe(int32(i%100 + 1))
}
}
func BenchmarkMasterList_HasCollection(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.HasCollection(int32(i%100 + 1))
}
}
func BenchmarkMasterList_FindCollectionsByCategory(b *testing.B) {
masterList := benchmarkSetup()
categories := []string{"Heritage", "Treasured", "Legendary", "Fabled", "Mythical"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.FindCollectionsByCategory(categories[i%len(categories)])
}
}
func BenchmarkMasterList_GetCollectionsByExactLevel(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
level := int8(i%50 + 1)
masterList.GetCollectionsByExactLevel(level)
}
}
func BenchmarkMasterList_FindCollectionsByLevel(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
minLevel := int8(i%45 + 1)
maxLevel := minLevel + 5
masterList.FindCollectionsByLevel(minLevel, maxLevel)
}
}
func BenchmarkMasterList_GetCollectionByName(b *testing.B) {
masterList := benchmarkSetup()
names := []string{"collection 1", "collection 25", "collection 50", "collection 75", "collection 100"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCollectionByName(names[i%len(names)])
}
}
func BenchmarkMasterList_NeedsItem(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
itemID := int32(i%100*1000 + 1001) // Various item IDs from the collections
masterList.NeedsItem(itemID)
}
}
func BenchmarkMasterList_GetCollectionsNeedingItem(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
itemID := int32(i%100*1000 + 1001) // Various item IDs from the collections
masterList.GetCollectionsNeedingItem(itemID)
}
}
func BenchmarkMasterList_GetCompletedCollections(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCompletedCollections()
}
}
func BenchmarkMasterList_GetIncompleteCollections(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetIncompleteCollections()
}
}
func BenchmarkMasterList_GetReadyToTurnInCollections(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetReadyToTurnInCollections()
}
}
func BenchmarkMasterList_GetCategories(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCategories()
}
}
func BenchmarkMasterList_GetLevels(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetLevels()
}
}
func BenchmarkMasterList_GetItemsNeeded(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetItemsNeeded()
}
}
func BenchmarkMasterList_GetAllCollections(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetAllCollections()
}
}
func BenchmarkMasterList_GetAllCollectionsList(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetAllCollectionsList()
}
}
func BenchmarkMasterList_GetStatistics(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetStatistics()
}
}
func BenchmarkMasterList_ValidateCollections(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.ValidateCollections()
}
}
func BenchmarkMasterList_RemoveCollection(b *testing.B) {
b.StopTimer()
masterList := benchmarkSetup()
initialCount := masterList.GetCollectionCount()
// Pre-populate with collections we'll remove
db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared")
for i := 0; i < b.N; i++ {
collection := NewWithData(int32(20000+i), fmt.Sprintf("ToRemove%d", i), "Temporary", 1, db)
collection.CollectionItems = []CollectionItem{
{ItemID: int32(60000 + i), Index: 0, Found: ItemNotFound},
}
masterList.AddCollection(collection)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
masterList.RemoveCollection(int32(20000 + i))
}
b.StopTimer()
if masterList.GetCollectionCount() != initialCount {
b.Errorf("Expected %d collections after removal, got %d", initialCount, masterList.GetCollectionCount())
}
}
func BenchmarkMasterList_ForEach(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
count := 0
masterList.ForEach(func(id int32, collection *Collection) {
count++
})
}
}
func BenchmarkMasterList_UpdateCollection(b *testing.B) {
masterList := benchmarkSetup()
db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared")
b.ResetTimer()
for i := 0; i < b.N; i++ {
collectionID := int32(i%100 + 1)
updatedCollection := &Collection{
ID: collectionID,
Name: fmt.Sprintf("Updated%d", i),
Category: "Updated",
Level: 25,
db: db,
isNew: false,
CollectionItems: []CollectionItem{
{ItemID: int32(i + 70000), Index: 0, Found: ItemNotFound},
},
}
masterList.UpdateCollection(updatedCollection)
}
}
func BenchmarkMasterList_RefreshCollectionIndices(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
collection := masterList.GetCollection(int32(i%100 + 1))
if collection != nil {
masterList.RefreshCollectionIndices(collection)
}
}
}
func BenchmarkMasterList_GetCollectionClone(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
for i := 0; i < b.N; i++ {
masterList.GetCollectionClone(int32(i%100 + 1))
}
}
// Memory allocation benchmarks
func BenchmarkMasterList_GetCollection_Allocs(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
masterList.GetCollection(int32(i%100 + 1))
}
}
func BenchmarkMasterList_FindCollectionsByCategory_Allocs(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
masterList.FindCollectionsByCategory("Heritage")
}
}
func BenchmarkMasterList_GetCollectionByName_Allocs(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
masterList.GetCollectionByName("collection 1")
}
}
func BenchmarkMasterList_NeedsItem_Allocs(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
masterList.NeedsItem(1001)
}
}
func BenchmarkMasterList_GetCollectionsNeedingItem_Allocs(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
masterList.GetCollectionsNeedingItem(1001)
}
}
// Concurrent benchmarks
func BenchmarkMasterList_ConcurrentReads(b *testing.B) {
masterList := benchmarkSetup()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Mix of read operations
switch b.N % 6 {
case 0:
masterList.GetCollection(int32(b.N%100 + 1))
case 1:
masterList.FindCollectionsByCategory("Heritage")
case 2:
masterList.GetCollectionByName("collection 1")
case 3:
masterList.NeedsItem(1001)
case 4:
masterList.GetCompletedCollections()
case 5:
masterList.GetCollectionsByExactLevel(10)
}
}
})
}
func BenchmarkMasterList_ConcurrentMixed(b *testing.B) {
masterList := benchmarkSetup()
db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared")
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// Mix of read and write operations (mostly reads)
switch b.N % 10 {
case 0: // 10% writes
collection := NewWithData(int32(b.N+50000), fmt.Sprintf("Concurrent%d", b.N), "Concurrent", 15, db)
collection.CollectionItems = []CollectionItem{
{ItemID: int32(b.N + 80000), Index: 0, Found: ItemNotFound},
}
masterList.AddCollection(collection)
default: // 90% reads
switch b.N % 5 {
case 0:
masterList.GetCollection(int32(b.N%100 + 1))
case 1:
masterList.FindCollectionsByCategory("Heritage")
case 2:
masterList.GetCollectionByName("collection 1")
case 3:
masterList.NeedsItem(1001)
case 4:
masterList.GetCompletedCollections()
}
}
}
})
}