package entity import ( "testing" ) func createTestManager() *Manager { return NewManager() } func createTestEntity() *Entity { entity := NewEntity() // Set some basic info for testing info := entity.GetInfoStruct() info.SetName("Test Entity") info.SetLevel(10) info.SetClass1(1) // Fighter info.SetRace(1) // Human info.SetGender(1) // Male info.SetStr(50.0) info.SetSta(45.0) info.SetAgi(40.0) info.SetWis(35.0) info.SetIntel(30.0) // Set HP and Power for testing entity.SetTotalHP(1000) entity.SetHP(1000) entity.SetTotalPower(500) entity.SetPower(500) return entity } // Test Manager Creation and Configuration func TestManagerCreation(t *testing.T) { manager := NewManager() if manager == nil { t.Fatal("NewManager returned nil") } // Check default configuration config := manager.GetConfiguration() if config["enable_statistics"].(bool) != true { t.Error("Expected statistics to be enabled by default") } if config["enable_validation"].(bool) != true { t.Error("Expected validation to be enabled by default") } if config["enable_pet_management"].(bool) != true { t.Error("Expected pet management to be enabled by default") } } // Test Entity Creation and Destruction func TestEntityCreationAndDestruction(t *testing.T) { manager := createTestManager() // Test entity creation entity := manager.CreateEntity() if entity == nil { t.Fatal("CreateEntity returned nil") } if entity.GetInfoStruct() == nil { t.Error("Entity info struct is nil") } // Check initial state if entity.IsInCombat() { t.Error("New entity should not be in combat") } if entity.IsCasting() { t.Error("New entity should not be casting") } // Test entity destruction err := manager.DestroyEntity(entity) if err != nil { t.Errorf("DestroyEntity failed: %v", err) } // Test destroying nil entity err = manager.DestroyEntity(nil) if err == nil { t.Error("Expected error when destroying nil entity") } } // Test Entity State Management func TestEntityStateManagement(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Test combat state if manager.IsEntityInCombat(entity) { t.Error("Entity should not be in combat initially") } manager.SetEntityInCombat(entity, true) if !manager.IsEntityInCombat(entity) { t.Error("Entity should be in combat after setting") } manager.SetEntityInCombat(entity, false) if manager.IsEntityInCombat(entity) { t.Error("Entity should not be in combat after unsetting") } // Test casting state if manager.IsEntityCasting(entity) { t.Error("Entity should not be casting initially") } manager.SetEntityCasting(entity, true) if !manager.IsEntityCasting(entity) { t.Error("Entity should be casting after setting") } manager.SetEntityCasting(entity, false) if manager.IsEntityCasting(entity) { t.Error("Entity should not be casting after unsetting") } // Test with nil entity if manager.IsEntityInCombat(nil) { t.Error("Nil entity should not be in combat") } if manager.IsEntityCasting(nil) { t.Error("Nil entity should not be casting") } } // Test InfoStruct Management func TestInfoStructManagement(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Test getting info struct info := manager.GetEntityInfoStruct(entity) if info == nil { t.Fatal("GetEntityInfoStruct returned nil") } if info.GetName() != "Test Entity" { t.Errorf("Expected 'Test Entity', got '%s'", info.GetName()) } if info.GetLevel() != 10 { t.Errorf("Expected level 10, got %d", info.GetLevel()) } // Test setting new info struct newInfo := NewInfoStruct() newInfo.SetName("Updated Entity") newInfo.SetLevel(20) manager.SetEntityInfoStruct(entity, newInfo) updatedInfo := manager.GetEntityInfoStruct(entity) if updatedInfo.GetName() != "Updated Entity" { t.Error("Info struct was not updated") } // Test with nil entity nilInfo := manager.GetEntityInfoStruct(nil) if nilInfo != nil { t.Error("Expected nil for nil entity info struct") } } // Test Spell Effect Management func TestSpellEffectManagement(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Test adding maintained spell success := manager.AddMaintainedSpell(entity, "Test Buff", 1001, 60.0, 1) if !success { t.Error("Failed to add maintained spell") } // Test getting maintained spell effect := entity.GetMaintainedSpell(1001) if effect == nil { t.Error("Failed to retrieve maintained spell") } // Test removing maintained spell success = manager.RemoveMaintainedSpell(entity, 1001) if !success { t.Error("Failed to remove maintained spell") } // Verify removal effect = entity.GetMaintainedSpell(1001) if effect != nil { t.Error("Maintained spell was not removed") } // Test adding temporary spell effect success = manager.AddSpellEffect(entity, 2001, 12345, 30.0) if !success { t.Error("Failed to add spell effect") } // Test removing spell effect success = manager.RemoveSpellEffect(entity, 2001) if !success { t.Error("Failed to remove spell effect") } // Test detrimental spell manager.AddDetrimentalSpell(entity, 3001, 12345, 45.0, 1) // Test removing detrimental spell success = manager.RemoveDetrimentalSpell(entity, 3001, 12345) if !success { t.Error("Failed to remove detrimental spell") } // Test with nil entity if manager.AddMaintainedSpell(nil, "Test", 1, 1.0, 1) { t.Error("Should not be able to add spell to nil entity") } } // Test Pet Management func TestPetManagement(t *testing.T) { manager := createTestManager() entity := createTestEntity() pet := createTestEntity() pet.GetInfoStruct().SetName("Test Pet") // Test setting summon pet manager.SetEntityPet(entity, pet) retrievedPet := manager.GetEntityPet(entity) if retrievedPet != pet { t.Error("Failed to set/get summon pet") } if pet.GetOwner() != entity.GetID() { t.Error("Pet owner was not set correctly") } if pet.GetPetType() != PetTypeSummon { t.Error("Pet type was not set correctly") } // Test charmed pet charmedPet := createTestEntity() charmedPet.GetInfoStruct().SetName("Charmed Pet") manager.SetEntityCharmedPet(entity, charmedPet) retrievedCharmed := manager.GetEntityCharmedPet(entity) if retrievedCharmed != charmedPet { t.Error("Failed to set/get charmed pet") } if charmedPet.GetPetType() != PetTypeCharm { t.Error("Charmed pet type was not set correctly") } // Test dismissing pet manager.DismissPet(pet) if !pet.IsPetDismissing() { t.Error("Pet was not marked for dismissal") } // Test with nil entities if manager.GetEntityPet(nil) != nil { t.Error("Expected nil for nil entity pet") } if manager.GetEntityCharmedPet(nil) != nil { t.Error("Expected nil for nil entity charmed pet") } } // Test Movement and Position func TestMovementAndPosition(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Set initial position entity.SetX(100.0) entity.SetY(200.0, false) entity.SetZ(300.0) entity.SetHeading(150, 150) // Heading is int16, not float // Update position tracking manager.UpdateEntityPosition(entity) // Check if position was recorded lastX, lastY, lastZ, lastHeading := entity.GetLastPosition() if lastX == -1 || lastY == -1 || lastZ == -1 || lastHeading == -1 { t.Error("Position was not updated correctly") } // Test movement detection (should not have moved yet) if manager.HasEntityMoved(entity) { t.Error("Entity should not have moved yet") } // Move entity entity.SetX(101.0) // Now should detect movement if !manager.HasEntityMoved(entity) { t.Error("Entity movement was not detected") } // Test speed calculation entity.SetMaxSpeed(10.0) entity.SetBaseSpeed(8.0) entity.SetSpeedMultiplier(1.5) speed := manager.GetEntityEffectiveSpeed(entity) expected := float32(8.0 * 1.5) // base * multiplier if speed != expected { t.Errorf("Expected speed %.2f, got %.2f", expected, speed) } // Test with nil entity if manager.HasEntityMoved(nil) { t.Error("Nil entity should not have moved") } if manager.GetEntityEffectiveSpeed(nil) != 0.0 { t.Error("Nil entity speed should be 0.0") } } // Test Stat Calculations func TestStatCalculations(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Test primary stat calculation primaryStat := manager.GetEntityPrimaryStat(entity) if primaryStat != 50 { // STR is highest at 50.0 t.Errorf("Expected primary stat 50, got %d", primaryStat) } // Test resistance calculations info := entity.GetInfoStruct() info.SetResistance("heat", 25) info.SetResistance("cold", 30) heatResist := manager.GetEntityResistance(entity, "heat") if heatResist != 25 { t.Errorf("Expected heat resistance 25, got %d", heatResist) } coldResist := manager.GetEntityResistance(entity, "cold") if coldResist != 30 { t.Errorf("Expected cold resistance 30, got %d", coldResist) } unknownResist := manager.GetEntityResistance(entity, "unknown") if unknownResist != 0 { t.Errorf("Expected unknown resistance 0, got %d", unknownResist) } // Test with nil entity if manager.GetEntityPrimaryStat(nil) != 0 { t.Error("Nil entity primary stat should be 0") } if manager.GetEntityResistance(nil, "heat") != 0 { t.Error("Nil entity resistance should be 0") } } // Test Bonus Calculations func TestBonusCalculations(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Calculate bonuses (this should recalculate all stats) manager.CalculateEntityBonuses(entity) // Stats should be recalculated (may be different due to effects) newStr := entity.GetStr() // Since we don't have spell effects, stats should remain the same or reset to base if newStr < 0 { t.Error("Strength should not be negative after bonus calculation") } } // Test Packet Building (these would normally require packet definitions) func TestPacketBuilding(t *testing.T) { manager := createTestManager() entityID := int32(12345) clientVersion := uint32(57048) // Test entity verbs request - should fail without packet definitions _, err := manager.SendEntityVerbsRequest(entityID, clientVersion) if err == nil { t.Error("Expected error for missing packet definition, but got none") } // Test entity verbs response - should fail without packet definitions verbs := []map[string]interface{}{ {"verb_id": 1, "verb_name": "examine"}, {"verb_id": 2, "verb_name": "attack"}, } _, err = manager.SendEntityVerbsResponse(entityID, clientVersion, verbs) if err == nil { t.Error("Expected error for missing packet definition, but got none") } // Test entity verb action - should fail without packet definitions _, err = manager.SendEntityVerbsVerb(entityID, 67890, clientVersion, 1, "examine") if err == nil { t.Error("Expected error for missing packet definition, but got none") } } // Test Effect Processing func TestEffectProcessing(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Add a spell effect manager.AddSpellEffect(entity, 1001, 12345, 30.0) // Process effects (should handle cleanup, etc.) manager.ProcessEntityEffects(entity) // Cleanup effects manager.CleanupEntityEffects(entity) // Test with nil entity (should not crash) manager.ProcessEntityEffects(nil) manager.CleanupEntityEffects(nil) } // Test Statistics and Monitoring func TestStatisticsAndMonitoring(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Perform some operations to generate statistics manager.CreateEntity() manager.SetEntityInCombat(entity, true) manager.AddSpellEffect(entity, 1001, 12345, 30.0) manager.RemoveSpellEffect(entity, 1001) manager.CalculateEntityBonuses(entity) stats := manager.GetStatistics() if stats == nil { t.Fatal("Statistics returned nil") } // Check some expected statistics exist if _, exists := stats["entities_created"]; !exists { t.Error("Expected entities_created statistic") } if _, exists := stats["spell_effects_added"]; !exists { t.Error("Expected spell_effects_added statistic") } if _, exists := stats["spell_effects_removed"]; !exists { t.Error("Expected spell_effects_removed statistic") } if _, exists := stats["bonus_calculations"]; !exists { t.Error("Expected bonus_calculations statistic") } if _, exists := stats["combat_actions"]; !exists { t.Error("Expected combat_actions statistic") } // Check that some statistics have non-zero values if stats["entities_created"].(int64) < 1 { t.Error("Expected at least 1 entity created") } if stats["spell_effects_added"].(int64) < 1 { t.Error("Expected at least 1 spell effect added") } // Test reset statistics manager.ResetStatistics() newStats := manager.GetStatistics() if newStats["entities_created"].(int64) != 0 { t.Error("Expected entities created to be reset to 0") } } // Test Configuration Management func TestConfigurationManagement(t *testing.T) { manager := createTestManager() // Test default configuration config := manager.GetConfiguration() if !config["enable_statistics"].(bool) { t.Error("Expected statistics to be enabled by default") } // Test configuration update newConfig := map[string]interface{}{ "enable_statistics": false, "enable_combat_logging": true, "max_entities_per_zone": 5000, } manager.SetConfiguration(newConfig) updatedConfig := manager.GetConfiguration() if updatedConfig["enable_statistics"].(bool) { t.Error("Expected statistics to be disabled after update") } if !updatedConfig["enable_combat_logging"].(bool) { t.Error("Expected combat logging to be enabled after update") } if updatedConfig["max_entities_per_zone"].(int) != 5000 { t.Error("Expected max_entities_per_zone to be updated to 5000") } } // Test Validation and Health Checks func TestValidationAndHealthChecks(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Test health check if !manager.IsHealthy() { t.Error("Manager should be healthy") } // Test entity validation issues := manager.ValidateEntity(entity) if len(issues) > 0 { t.Errorf("Expected no validation issues, got %d: %v", len(issues), issues) } // Test validation with invalid entity invalidEntity := createTestEntity() invalidEntity.GetInfoStruct().SetLevel(-1) invalidEntity.GetInfoStruct().SetName("") invalidEntity.SetTotalHP(-100) validationIssues := manager.ValidateEntity(invalidEntity) if len(validationIssues) == 0 { t.Error("Expected validation issues for invalid entity") } // Check specific issues (should have at least 3 issues) if len(validationIssues) < 3 { t.Errorf("Expected at least 3 validation issues, got %d: %v", len(validationIssues), validationIssues) } // Test validation with nil entity nilIssues := manager.ValidateEntity(nil) if len(nilIssues) != 1 || nilIssues[0] != "entity is nil" { t.Error("Expected 'entity is nil' issue for nil entity") } } // Test Thread Safety (basic test) func TestThreadSafety(t *testing.T) { manager := createTestManager() entity := createTestEntity() // Perform concurrent operations done := make(chan bool, 10) // Start multiple goroutines performing different operations for i := 0; i < 10; i++ { go func(id int) { defer func() { done <- true }() // Mix of read and write operations manager.GetEntityInfoStruct(entity) manager.SetEntityInCombat(entity, true) manager.SetEntityInCombat(entity, false) manager.GetStatistics() manager.CalculateEntityBonuses(entity) manager.ProcessEntityEffects(entity) }(i) } // Wait for all goroutines to complete for i := 0; i < 10; i++ { <-done } // Manager should still be functional if !manager.IsHealthy() { t.Error("Manager appears corrupted after concurrent access") } } // Test Entity Stat Methods func TestEntityStatMethods(t *testing.T) { entity := createTestEntity() // Test individual stat getters if entity.GetStr() != 50 { t.Errorf("Expected STR 50, got %d", entity.GetStr()) } if entity.GetSta() != 45 { t.Errorf("Expected STA 45, got %d", entity.GetSta()) } if entity.GetAgi() != 40 { t.Errorf("Expected AGI 40, got %d", entity.GetAgi()) } if entity.GetWis() != 35 { t.Errorf("Expected WIS 35, got %d", entity.GetWis()) } if entity.GetIntel() != 30 { t.Errorf("Expected INT 30, got %d", entity.GetIntel()) } // Test primary stat calculation primary := entity.GetPrimaryStat() if primary != 50 { // STR is highest t.Errorf("Expected primary stat 50, got %d", primary) } } // Test Entity Health and Power func TestEntityHealthAndPower(t *testing.T) { entity := createTestEntity() // Test initial values if entity.GetTotalHP() != 1000 { t.Errorf("Expected total HP 1000, got %d", entity.GetTotalHP()) } if entity.GetHP() != 1000 { t.Errorf("Expected current HP 1000, got %d", entity.GetHP()) } if entity.GetTotalPower() != 500 { t.Errorf("Expected total power 500, got %d", entity.GetTotalPower()) } if entity.GetPower() != 500 { t.Errorf("Expected current power 500, got %d", entity.GetPower()) } // Test alive state if !entity.IsAlive() { t.Error("Entity should be alive with positive HP") } if entity.IsDead() { t.Error("Entity should not be dead with positive HP") } // Test setting HP to 0 entity.SetHP(0) entity.SetAlive(false) // Need to explicitly set alive state if entity.IsAlive() { t.Error("Entity should not be alive with 0 HP") } if !entity.IsDead() { t.Error("Entity should be dead with 0 HP") } } // Test InfoStruct Methods func TestInfoStructMethods(t *testing.T) { info := NewInfoStruct() // Test basic properties info.SetName("Test Character") if info.GetName() != "Test Character" { t.Error("Name was not set correctly") } info.SetLevel(25) if info.GetLevel() != 25 { t.Error("Level was not set correctly") } info.SetClass1(5) if info.GetClass1() != 5 { t.Error("Class was not set correctly") } info.SetRace(2) if info.GetRace() != 2 { t.Error("Race was not set correctly") } // Test concentration system info.SetMaxConcentration(10) if info.GetMaxConcentration() != 10 { t.Error("Max concentration was not set correctly") } success := info.AddConcentration(5) if !success { t.Error("Failed to add concentration") } if info.GetCurConcentration() != 5 { t.Error("Current concentration was not updated correctly") } // Try to add too much concentration success = info.AddConcentration(10) if success { t.Error("Should not be able to add more concentration than available") } // Remove concentration info.RemoveConcentration(3) if info.GetCurConcentration() != 2 { t.Error("Concentration was not removed correctly") } // Test coin system info.AddCoins(1234567) // 1.23 plat, 45 gold, 67 copper totalCoins := info.GetCoins() if totalCoins != 1234567 { t.Errorf("Expected %d total coins, got %d", 1234567, totalCoins) } // Test removing coins success = info.RemoveCoins(100000) if !success { t.Error("Failed to remove coins") } newTotal := info.GetCoins() if newTotal != 1134567 { t.Errorf("Expected %d coins after removal, got %d", 1134567, newTotal) } // Try to remove more coins than available success = info.RemoveCoins(2000000) if success { t.Error("Should not be able to remove more coins than available") } } // Test InfoStruct Clone func TestInfoStructClone(t *testing.T) { original := NewInfoStruct() original.SetName("Original") original.SetLevel(50) original.SetStr(100.0) original.AddCoins(5000) clone := original.Clone() if clone == nil { t.Fatal("Clone returned nil") } // Verify clone has same data if clone.GetName() != original.GetName() { t.Error("Clone has different name") } if clone.GetLevel() != original.GetLevel() { t.Error("Clone has different level") } if clone.GetStr() != original.GetStr() { t.Error("Clone has different strength") } if clone.GetCoins() != original.GetCoins() { t.Error("Clone has different coins") } // Verify clone is independent clone.SetName("Modified Clone") if original.GetName() == "Modified Clone" { t.Error("Modifying clone affected original") } } // Benchmark tests func BenchmarkCreateEntity(b *testing.B) { manager := createTestManager() b.ResetTimer() for i := 0; i < b.N; i++ { manager.CreateEntity() } } func BenchmarkGetEntityInfoStruct(b *testing.B) { manager := createTestManager() entity := createTestEntity() b.ResetTimer() for i := 0; i < b.N; i++ { manager.GetEntityInfoStruct(entity) } } func BenchmarkCalculateEntityBonuses(b *testing.B) { manager := createTestManager() entity := createTestEntity() b.ResetTimer() for i := 0; i < b.N; i++ { manager.CalculateEntityBonuses(entity) } } func BenchmarkGetStatistics(b *testing.B) { manager := createTestManager() b.ResetTimer() for i := 0; i < b.N; i++ { manager.GetStatistics() } }