package chat 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 world channels worldChannels := []string{ "Auction", "Trade", "General", "OOC", "LFG", "Crafting", "Roleplay", "Newbie", "Antonica", "Commonlands", "Freeport", "Qeynos", "Kelethin", "Neriak", } for i, name := range worldChannels { ch := NewWithData(int32(i+1), name, ChannelTypeWorld, db) if i%3 == 0 { ch.SetLevelRestriction(10) // Some have level restrictions } if i%4 == 0 { ch.SetRacesAllowed(1 << 1) // Some have race restrictions } masterList.AddChannel(ch) // Add some members to channels if i%2 == 0 { ch.JoinChannel(int32(1000 + i)) } if i%3 == 0 { ch.JoinChannel(int32(2000 + i)) } } // Add custom channels for i := 0; i < 50; i++ { ch := NewWithData(int32(100+i), fmt.Sprintf("CustomChannel%d", i), ChannelTypeCustom, db) if i%5 == 0 { ch.SetLevelRestriction(20) } masterList.AddChannel(ch) // Add members to some custom channels if i%4 == 0 { ch.JoinChannel(int32(3000 + i)) } } return masterList } func BenchmarkMasterList_AddChannel(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++ { ch := NewWithData(int32(i+10000), fmt.Sprintf("Channel%d", i), ChannelTypeWorld, db) masterList.AddChannel(ch) } } func BenchmarkMasterList_GetChannel(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetChannel(int32(i%64 + 1)) } } func BenchmarkMasterList_GetChannelSafe(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetChannelSafe(int32(i%64 + 1)) } } func BenchmarkMasterList_HasChannel(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.HasChannel(int32(i%64 + 1)) } } func BenchmarkMasterList_FindChannelsByType(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { if i%2 == 0 { masterList.FindChannelsByType(ChannelTypeWorld) } else { masterList.FindChannelsByType(ChannelTypeCustom) } } } func BenchmarkMasterList_GetWorldChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetWorldChannels() } } func BenchmarkMasterList_GetCustomChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetCustomChannels() } } func BenchmarkMasterList_GetChannelByName(b *testing.B) { masterList := benchmarkSetup() names := []string{"auction", "trade", "general", "ooc", "customchannel5", "customchannel15"} b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetChannelByName(names[i%len(names)]) } } func BenchmarkMasterList_FindChannelsByName(b *testing.B) { masterList := benchmarkSetup() searchTerms := []string{"Auction", "Custom", "Channel", "Trade", "General"} b.ResetTimer() for i := 0; i < b.N; i++ { masterList.FindChannelsByName(searchTerms[i%len(searchTerms)]) } } func BenchmarkMasterList_GetActiveChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetActiveChannels() } } func BenchmarkMasterList_GetEmptyChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetEmptyChannels() } } func BenchmarkMasterList_GetCompatibleChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { level := int32(i%50 + 1) race := int32(i%10 + 1) class := int32(i%20 + 1) masterList.GetCompatibleChannels(level, race, class) } } func BenchmarkMasterList_GetChannelsByMemberCount(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { memberCount := i % 5 // 0-4 members masterList.GetChannelsByMemberCount(memberCount) } } func BenchmarkMasterList_GetChannelsByLevelRestriction(b *testing.B) { masterList := benchmarkSetup() levels := []int32{0, 10, 20, 30, 50} b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetChannelsByLevelRestriction(levels[i%len(levels)]) } } func BenchmarkMasterList_GetAllChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetAllChannels() } } func BenchmarkMasterList_GetAllChannelsList(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetAllChannelsList() } } func BenchmarkMasterList_GetStatistics(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.GetStatistics() } } func BenchmarkMasterList_ValidateChannels(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { masterList.ValidateChannels() } } func BenchmarkMasterList_RemoveChannel(b *testing.B) { b.StopTimer() masterList := benchmarkSetup() initialCount := masterList.GetChannelCount() // Pre-populate with channels we'll remove db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") for i := 0; i < b.N; i++ { ch := NewWithData(int32(20000+i), fmt.Sprintf("ToRemove%d", i), ChannelTypeCustom, db) masterList.AddChannel(ch) } b.StartTimer() for i := 0; i < b.N; i++ { masterList.RemoveChannel(int32(20000 + i)) } b.StopTimer() if masterList.GetChannelCount() != initialCount { b.Errorf("Expected %d channels after removal, got %d", initialCount, masterList.GetChannelCount()) } } func BenchmarkMasterList_ForEach(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() for i := 0; i < b.N; i++ { count := 0 masterList.ForEach(func(id int32, channel *Channel) { count++ }) } } func BenchmarkMasterList_UpdateChannel(b *testing.B) { masterList := benchmarkSetup() db, _ := database.NewSQLite("file::memory:?mode=memory&cache=shared") b.ResetTimer() for i := 0; i < b.N; i++ { channelID := int32(i%64 + 1) updatedChannel := &Channel{ ID: channelID, Name: fmt.Sprintf("Updated%d", i), ChannelType: ChannelTypeCustom, db: db, isNew: false, members: make([]int32, 0), } masterList.UpdateChannel(updatedChannel) } } // Memory allocation benchmarks func BenchmarkMasterList_GetChannel_Allocs(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { masterList.GetChannel(int32(i%64 + 1)) } } func BenchmarkMasterList_FindChannelsByType_Allocs(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { masterList.FindChannelsByType(ChannelTypeWorld) } } func BenchmarkMasterList_GetChannelByName_Allocs(b *testing.B) { masterList := benchmarkSetup() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { masterList.GetChannelByName("auction") } } // Concurrent benchmark 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 % 5 { case 0: masterList.GetChannel(int32(b.N%64 + 1)) case 1: masterList.FindChannelsByType(ChannelTypeWorld) case 2: masterList.GetChannelByName("auction") case 3: masterList.GetActiveChannels() case 4: masterList.GetCompatibleChannels(25, 1, 1) } } }) } 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 ch := NewWithData(int32(b.N+50000), fmt.Sprintf("Concurrent%d", b.N), ChannelTypeCustom, db) masterList.AddChannel(ch) default: // 90% reads switch b.N % 4 { case 0: masterList.GetChannel(int32(b.N%64 + 1)) case 1: masterList.FindChannelsByType(ChannelTypeWorld) case 2: masterList.GetChannelByName("auction") case 3: masterList.GetActiveChannels() } } } }) }