package factions import ( "fmt" "testing" ) // Benchmark MasterFactionList operations func BenchmarkMasterFactionList(b *testing.B) { b.Run("GetFaction", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 1000) + 1) _ = mfl.GetFaction(factionID) } }) b.Run("GetFactionByName", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetFactionByName("Benchmark Faction") } }) b.Run("AddFaction", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32(2000 + i) faction := NewFaction(factionID, "New Faction", "Test", "New test") mfl.AddFaction(faction) } }) b.Run("GetFactionCount", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetFactionCount() } }) b.Run("AddHostileFaction", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 1000) + 1) hostileID := int32(((i + 1) % 1000) + 1) mfl.AddHostileFaction(factionID, hostileID) } }) b.Run("GetHostileFactions", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions and some hostile relationships for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } // Add a reasonable number of hostile relationships for i := int32(1); i <= 100; i++ { for j := int32(1); j <= 5; j++ { mfl.AddHostileFaction(i, i+j) } } b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = mfl.GetHostileFactions(factionID) } }) b.Run("ValidateFactions", func(b *testing.B) { mfl := NewMasterList() // Pre-populate with factions for i := int32(1); i <= 1000; i++ { faction := NewFaction(i, "Benchmark Faction", "Test", "Benchmark test") mfl.AddFaction(faction) } // Add some hostile relationships for realistic validation for i := int32(1); i <= 100; i++ { mfl.AddHostileFaction(i, i+1) } b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.ValidateFactions() } }) } // Benchmark PlayerFaction operations func BenchmarkPlayerFaction(b *testing.B) { mfl := NewMasterList() // Setup factions with proper values for i := int32(1); i <= 100; i++ { faction := NewFaction(i, "Player Faction", "Test", "Player test") faction.PositiveChange = 100 faction.NegativeChange = 50 mfl.AddFaction(faction) } pf := NewPlayerFaction(mfl) // Pre-populate some faction values for i := int32(1); i <= 100; i++ { pf.SetFactionValue(i, int32(i*1000)) } b.Run("GetFactionValue", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = pf.GetFactionValue(factionID) } }) b.Run("SetFactionValue", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) pf.SetFactionValue(factionID, int32(i)) } }) b.Run("IncreaseFaction", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) pf.IncreaseFaction(factionID, 10) } }) b.Run("DecreaseFaction", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) pf.DecreaseFaction(factionID, 5) } }) b.Run("GetCon", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = pf.GetCon(factionID) } }) b.Run("GetPercent", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = pf.GetPercent(factionID) } }) b.Run("ShouldAttack", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = pf.ShouldAttack(factionID) } }) b.Run("FactionUpdate", func(b *testing.B) { // Trigger some updates first for i := int32(1); i <= 10; i++ { pf.IncreaseFaction(i, 1) } b.ResetTimer() for i := 0; i < b.N; i++ { pf.FactionUpdate(int16(i % 10)) } }) } // Benchmark Manager operations func BenchmarkManager(b *testing.B) { manager := NewManager(nil, nil) // Pre-populate with factions for i := int32(1); i <= 100; i++ { faction := NewFaction(i, "Manager Faction", "Test", "Manager test") manager.AddFaction(faction) } b.Run("GetFaction", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) _ = manager.GetFaction(factionID) } }) b.Run("CreatePlayerFaction", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = manager.CreatePlayerFaction() } }) b.Run("RecordFactionIncrease", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) manager.RecordFactionIncrease(factionID) } }) b.Run("RecordFactionDecrease", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 100) + 1) manager.RecordFactionDecrease(factionID) } }) b.Run("GetStatistics", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = manager.GetStatistics() } }) b.Run("ValidateAllFactions", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = manager.ValidateAllFactions() } }) } // Benchmark EntityFactionAdapter operations func BenchmarkEntityFactionAdapter(b *testing.B) { manager := NewManager(nil, nil) entity := &mockEntity{id: 123, name: "Benchmark Entity", dbID: 456} adapter := NewEntityFactionAdapter(entity, manager, nil) // Set up factions and relationships for i := int32(1); i <= 10; i++ { faction := NewFaction(i, "Entity Faction", "Test", "Entity test") manager.AddFaction(faction) } mfl := manager.GetMasterFactionList() mfl.AddHostileFaction(1, 2) mfl.AddFriendlyFaction(1, 3) b.Run("GetFactionID", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { _ = adapter.GetFactionID() } }) b.Run("SetFactionID", func(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 10) + 1) adapter.SetFactionID(factionID) } }) b.Run("GetFaction", func(b *testing.B) { adapter.SetFactionID(1) b.ResetTimer() for i := 0; i < b.N; i++ { _ = adapter.GetFaction() } }) b.Run("IsHostileToFaction", func(b *testing.B) { adapter.SetFactionID(1) b.ResetTimer() for i := 0; i < b.N; i++ { targetID := int32((i % 10) + 1) _ = adapter.IsHostileToFaction(targetID) } }) b.Run("IsFriendlyToFaction", func(b *testing.B) { adapter.SetFactionID(1) b.ResetTimer() for i := 0; i < b.N; i++ { targetID := int32((i % 10) + 1) _ = adapter.IsFriendlyToFaction(targetID) } }) b.Run("ValidateFaction", func(b *testing.B) { adapter.SetFactionID(1) b.ResetTimer() for i := 0; i < b.N; i++ { _ = adapter.ValidateFaction() } }) } // Benchmark concurrent operations func BenchmarkConcurrentOperations(b *testing.B) { b.Run("MasterFactionListConcurrent", func(b *testing.B) { mfl := NewMasterList() // Pre-populate for i := int32(1); i <= 100; i++ { faction := NewFaction(i, "Concurrent Faction", "Test", "Concurrent test") mfl.AddFaction(faction) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { factionID := int32((i % 100) + 1) _ = mfl.GetFaction(factionID) i++ } }) }) b.Run("PlayerFactionConcurrent", func(b *testing.B) { mfl := NewMasterList() for i := int32(1); i <= 10; i++ { faction := NewFaction(i, "Player Faction", "Test", "Player test") faction.PositiveChange = 100 mfl.AddFaction(faction) } pf := NewPlayerFaction(mfl) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { factionID := int32((i % 10) + 1) switch i % 4 { case 0: _ = pf.GetFactionValue(factionID) case 1: pf.IncreaseFaction(factionID, 1) case 2: _ = pf.GetCon(factionID) case 3: _ = pf.GetPercent(factionID) } i++ } }) }) b.Run("ManagerConcurrent", func(b *testing.B) { manager := NewManager(nil, nil) // Pre-populate for i := int32(1); i <= 10; i++ { faction := NewFaction(i, "Manager Faction", "Test", "Manager test") manager.AddFaction(faction) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { factionID := int32((i % 10) + 1) switch i % 4 { case 0: _ = manager.GetFaction(factionID) case 1: manager.RecordFactionIncrease(factionID) case 2: _ = manager.GetStatistics() case 3: _ = manager.CreatePlayerFaction() } i++ } }) }) } // Memory allocation benchmarks func BenchmarkMemoryAllocations(b *testing.B) { b.Run("FactionCreation", func(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = NewFaction(int32(i), "Memory Test", "Test", "Memory test") } }) b.Run("MasterFactionListCreation", func(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = NewMasterList() } }) b.Run("PlayerFactionCreation", func(b *testing.B) { mfl := NewMasterList() b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = NewPlayerFaction(mfl) } }) b.Run("ManagerCreation", func(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = NewManager(nil, nil) } }) b.Run("EntityAdapterCreation", func(b *testing.B) { manager := NewManager(nil, nil) entity := &mockEntity{id: 123, name: "Memory Entity", dbID: 456} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { _ = NewEntityFactionAdapter(entity, manager, nil) } }) } // Contention benchmarks func BenchmarkContention(b *testing.B) { b.Run("HighContentionReads", func(b *testing.B) { mfl := NewMasterList() // Add a single faction that will be accessed heavily faction := NewFaction(1, "Contention Test", "Test", "Contention test") mfl.AddFaction(faction) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _ = mfl.GetFaction(1) } }) }) b.Run("HighContentionWrites", func(b *testing.B) { mfl := NewMasterList() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { factionID := int32(1000000 + i) // Unique IDs to avoid conflicts faction := NewFaction(factionID, "Write Test", "Test", "Write test") mfl.AddFaction(faction) i++ } }) }) b.Run("MixedReadWrite", func(b *testing.B) { mfl := NewMasterList() // Pre-populate for i := int32(1); i <= 100; i++ { faction := NewFaction(i, "Mixed Test", "Test", "Mixed test") mfl.AddFaction(faction) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { if i%10 == 0 { // 10% writes factionID := int32(2000000 + i) faction := NewFaction(factionID, "New Mixed", "Test", "New mixed") mfl.AddFaction(faction) } else { // 90% reads factionID := int32((i % 100) + 1) _ = mfl.GetFaction(factionID) } i++ } }) }) } // Scalability benchmarks func BenchmarkScalability(b *testing.B) { sizes := []int{10, 100, 1000, 10000} for _, size := range sizes { b.Run("FactionLookup_"+string(rune(size)), func(b *testing.B) { mfl := NewMasterList() // Pre-populate with varying sizes for i := int32(1); i <= int32(size); i++ { faction := NewFaction(i, "Scale Test", "Test", "Scale test") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % size) + 1) _ = mfl.GetFaction(factionID) } }) } } // Benchmark bespoke MasterList features func BenchmarkMasterListBespokeFeatures(b *testing.B) { // Setup function for consistent test data setupMasterList := func() *MasterList { mfl := NewMasterList() // Add factions across different types types := []string{"City", "Guild", "Religion", "Race", "Organization"} for i := 1; i <= 1000; i++ { factionType := types[i%len(types)] faction := NewFaction(int32(i), fmt.Sprintf("Faction%d", i), factionType, "Benchmark test") mfl.AddFaction(faction) } return mfl } b.Run("GetFactionSafe", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 1000) + 1) _, _ = mfl.GetFactionSafe(factionID) } }) b.Run("GetFactionByName", func(b *testing.B) { mfl := setupMasterList() names := []string{"faction1", "faction50", "faction100", "faction500", "faction1000"} b.ResetTimer() for i := 0; i < b.N; i++ { name := names[i%len(names)] _ = mfl.GetFactionByName(name) } }) b.Run("GetFactionsByType", func(b *testing.B) { mfl := setupMasterList() types := []string{"City", "Guild", "Religion", "Race", "Organization"} b.ResetTimer() for i := 0; i < b.N; i++ { factionType := types[i%len(types)] _ = mfl.GetFactionsByType(factionType) } }) b.Run("GetSpecialFactions", func(b *testing.B) { mfl := setupMasterList() // Add some special factions for i := int32(1); i <= 5; i++ { faction := NewFaction(i, fmt.Sprintf("Special%d", i), "Special", "Special faction") mfl.AddFaction(faction) } b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetSpecialFactions() } }) b.Run("GetRegularFactions", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetRegularFactions() } }) b.Run("GetTypes", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetTypes() } }) b.Run("GetAllFactionsList", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetAllFactionsList() } }) b.Run("GetFactionIDs", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetFactionIDs() } }) b.Run("UpdateFaction", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { factionID := int32((i % 1000) + 1) updatedFaction := &Faction{ ID: factionID, Name: fmt.Sprintf("Updated%d", i), Type: "Updated", Description: "Updated faction", } mfl.UpdateFaction(updatedFaction) } }) b.Run("ForEach", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { count := 0 mfl.ForEach(func(id int32, faction *Faction) { count++ }) } }) b.Run("GetStatistics", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() for i := 0; i < b.N; i++ { _ = mfl.GetStatistics() } }) b.Run("RemoveFaction", func(b *testing.B) { b.StopTimer() mfl := setupMasterList() initialCount := mfl.GetFactionCount() // Pre-populate with factions we'll remove for i := 0; i < b.N; i++ { faction := NewFaction(int32(20000+i), fmt.Sprintf("ToRemove%d", i), "Temporary", "Temporary faction") mfl.AddFaction(faction) } b.StartTimer() for i := 0; i < b.N; i++ { mfl.RemoveFaction(int32(20000 + i)) } b.StopTimer() if mfl.GetFactionCount() != initialCount { b.Errorf("Expected %d factions after removal, got %d", initialCount, mfl.GetFactionCount()) } }) } // Memory allocation benchmarks for bespoke features func BenchmarkMasterListBespokeFeatures_Allocs(b *testing.B) { setupMasterList := func() *MasterList { mfl := NewMasterList() types := []string{"City", "Guild", "Religion", "Race", "Organization"} for i := 1; i <= 100; i++ { factionType := types[i%len(types)] faction := NewFaction(int32(i), fmt.Sprintf("Faction%d", i), factionType, "Benchmark test") mfl.AddFaction(faction) } return mfl } b.Run("GetFactionByName_Allocs", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = mfl.GetFactionByName("faction1") } }) b.Run("GetFactionsByType_Allocs", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = mfl.GetFactionsByType("City") } }) b.Run("GetTypes_Allocs", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = mfl.GetTypes() } }) b.Run("GetSpecialFactions_Allocs", func(b *testing.B) { mfl := setupMasterList() // Add some special factions for i := int32(1); i <= 5; i++ { faction := NewFaction(i, fmt.Sprintf("Special%d", i), "Special", "Special faction") mfl.AddFaction(faction) } b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = mfl.GetSpecialFactions() } }) b.Run("GetStatistics_Allocs", func(b *testing.B) { mfl := setupMasterList() b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { _ = mfl.GetStatistics() } }) } // Concurrent benchmarks for bespoke features func BenchmarkMasterListBespokeConcurrent(b *testing.B) { b.Run("ConcurrentReads", func(b *testing.B) { mfl := NewMasterList() // Setup test data types := []string{"City", "Guild", "Religion", "Race", "Organization"} for i := 1; i <= 100; i++ { factionType := types[i%len(types)] faction := NewFaction(int32(i), fmt.Sprintf("Faction%d", i), factionType, "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { // Mix of read operations switch i % 6 { case 0: mfl.GetFaction(int32(i%100 + 1)) case 1: mfl.GetFactionsByType("City") case 2: mfl.GetFactionByName("faction1") case 3: mfl.GetSpecialFactions() case 4: mfl.GetRegularFactions() case 5: mfl.GetTypes() } i++ } }) }) b.Run("ConcurrentMixed", func(b *testing.B) { mfl := NewMasterList() // Setup test data types := []string{"City", "Guild", "Religion", "Race", "Organization"} for i := 1; i <= 100; i++ { factionType := types[i%len(types)] faction := NewFaction(int32(i), fmt.Sprintf("Faction%d", i), factionType, "Benchmark test") mfl.AddFaction(faction) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { // Mix of read and write operations (mostly reads) switch i % 10 { case 0: // 10% writes faction := NewFaction(int32(i+50000), fmt.Sprintf("Concurrent%d", i), "Concurrent", "Concurrent test") mfl.AddFaction(faction) default: // 90% reads switch i % 5 { case 0: mfl.GetFaction(int32(i%100 + 1)) case 1: mfl.GetFactionsByType("City") case 2: mfl.GetFactionByName("faction1") case 3: mfl.GetSpecialFactions() case 4: mfl.GetTypes() } } i++ } }) }) }