package entity import ( "sync" "testing" "time" ) func TestNewEntity(t *testing.T) { entity := NewEntity() if entity == nil { t.Fatal("NewEntity returned nil") } if entity.Spawn == nil { t.Error("Expected Spawn to be initialized") } if entity.infoStruct == nil { t.Error("Expected InfoStruct to be initialized") } if entity.spellEffectManager == nil { t.Error("Expected SpellEffectManager to be initialized") } // Check default values if entity.GetMaxSpeed() != 6.0 { t.Errorf("Expected max speed 6.0, got %f", entity.GetMaxSpeed()) } if entity.GetBaseSpeed() != 0.0 { t.Errorf("Expected base speed 0.0, got %f", entity.GetBaseSpeed()) } if entity.GetSpeedMultiplier() != 1.0 { t.Errorf("Expected speed multiplier 1.0, got %f", entity.GetSpeedMultiplier()) } // Check initial states if entity.IsInCombat() { t.Error("Expected entity to not be in combat initially") } if entity.IsCasting() { t.Error("Expected entity to not be casting initially") } if entity.IsPetDismissing() { t.Error("Expected pet to not be dismissing initially") } if entity.HasSeeInvisSpell() { t.Error("Expected entity to not have see invisible spell initially") } if entity.HasSeeHideSpell() { t.Error("Expected entity to not have see hidden spell initially") } } func TestEntityIsEntity(t *testing.T) { entity := NewEntity() if !entity.IsEntity() { t.Error("Expected IsEntity to return true") } } func TestEntityInfoStruct(t *testing.T) { entity := NewEntity() stats := entity.GetInfoStruct() if stats == nil { t.Error("Expected InfoStruct to be initialized") } // Test setting a new info struct newInfo := NewInfoStruct() newInfo.SetName("Test Entity") entity.SetInfoStruct(newInfo) if entity.GetInfoStruct().GetName() != "Test Entity" { t.Error("Expected info struct to be updated") } // Test that nil info struct is ignored entity.SetInfoStruct(nil) if entity.GetInfoStruct().GetName() != "Test Entity" { t.Error("Expected info struct to remain unchanged when setting nil") } } func TestEntityClient(t *testing.T) { entity := NewEntity() // Base Entity should return nil for GetClient client := entity.GetClient() if client != nil { t.Error("Expected GetClient to return nil for base Entity") } } func TestEntityCombatState(t *testing.T) { entity := NewEntity() // Initial state should be false if entity.IsInCombat() { t.Error("Expected entity to not be in combat initially") } // Set combat state to true entity.SetInCombat(true) if !entity.IsInCombat() { t.Error("Expected entity to be in combat after setting to true") } // Set combat state to false entity.SetInCombat(false) if entity.IsInCombat() { t.Error("Expected entity to not be in combat after setting to false") } } func TestEntityCastingState(t *testing.T) { entity := NewEntity() // Initial state should be false if entity.IsCasting() { t.Error("Expected entity to not be casting initially") } // Set casting state to true entity.SetCasting(true) if !entity.IsCasting() { t.Error("Expected entity to be casting after setting to true") } // Set casting state to false entity.SetCasting(false) if entity.IsCasting() { t.Error("Expected entity to not be casting after setting to false") } } func TestEntitySpeedMethods(t *testing.T) { entity := NewEntity() // Test max speed entity.SetMaxSpeed(10.0) if entity.GetMaxSpeed() != 10.0 { t.Errorf("Expected max speed 10.0, got %f", entity.GetMaxSpeed()) } // Test base speed entity.SetBaseSpeed(5.0) if entity.GetBaseSpeed() != 5.0 { t.Errorf("Expected base speed 5.0, got %f", entity.GetBaseSpeed()) } // Test speed multiplier entity.SetSpeedMultiplier(2.0) if entity.GetSpeedMultiplier() != 2.0 { t.Errorf("Expected speed multiplier 2.0, got %f", entity.GetSpeedMultiplier()) } // Test effective speed calculation with base speed set effectiveSpeed := entity.CalculateEffectiveSpeed() if effectiveSpeed != 10.0 { // 5.0 * 2.0 t.Errorf("Expected effective speed 10.0, got %f", effectiveSpeed) } // Test effective speed calculation with zero base speed (should use max speed) entity.SetBaseSpeed(0.0) effectiveSpeed = entity.CalculateEffectiveSpeed() if effectiveSpeed != 20.0 { // 10.0 * 2.0 t.Errorf("Expected effective speed 20.0, got %f", effectiveSpeed) } } func TestEntityPositionTracking(t *testing.T) { entity := NewEntity() // Test setting and getting last position entity.SetLastPosition(100.0, 200.0, 300.0, 1.5) x, y, z, heading := entity.GetLastPosition() if x != 100.0 || y != 200.0 || z != 300.0 || heading != 1.5 { t.Errorf("Expected position (100.0, 200.0, 300.0, 1.5), got (%f, %f, %f, %f)", x, y, z, heading) } // Test HasMoved with different positions // Note: This would require setting the spawn's actual position, which depends on the spawn implementation // For now, we just test that the method doesn't panic moved := entity.HasMoved() _ = moved // We can't easily test the actual movement detection without setting up spawn positions } func TestEntityStatCalculation(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() // Set base stats info.SetStr(10.0) info.SetSta(12.0) info.SetAgi(8.0) info.SetWis(15.0) info.SetIntel(20.0) // Test individual stat getters (these include bonuses from spell effects) str := entity.GetStr() if str < 10 { t.Errorf("Expected strength >= 10, got %d", str) } sta := entity.GetSta() if sta < 12 { t.Errorf("Expected stamina >= 12, got %d", sta) } agi := entity.GetAgi() if agi < 8 { t.Errorf("Expected agility >= 8, got %d", agi) } wis := entity.GetWis() if wis < 15 { t.Errorf("Expected wisdom >= 15, got %d", wis) } intel := entity.GetIntel() if intel < 20 { t.Errorf("Expected intelligence >= 20, got %d", intel) } // Test primary stat calculation primaryStat := entity.GetPrimaryStat() if primaryStat < 20 { t.Errorf("Expected primary stat >= 20 (intelligence is highest), got %d", primaryStat) } } func TestEntityResistances(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() // Set base resistances info.SetResistance("heat", 10) info.SetResistance("cold", 15) info.SetResistance("magic", 20) info.SetResistance("mental", 25) info.SetResistance("divine", 30) info.SetResistance("disease", 35) info.SetResistance("poison", 40) // Test resistance getters if entity.GetHeatResistance() != 10 { t.Errorf("Expected heat resistance 10, got %d", entity.GetHeatResistance()) } if entity.GetColdResistance() != 15 { t.Errorf("Expected cold resistance 15, got %d", entity.GetColdResistance()) } if entity.GetMagicResistance() != 20 { t.Errorf("Expected magic resistance 20, got %d", entity.GetMagicResistance()) } if entity.GetMentalResistance() != 25 { t.Errorf("Expected mental resistance 25, got %d", entity.GetMentalResistance()) } if entity.GetDivineResistance() != 30 { t.Errorf("Expected divine resistance 30, got %d", entity.GetDivineResistance()) } if entity.GetDiseaseResistance() != 35 { t.Errorf("Expected disease resistance 35, got %d", entity.GetDiseaseResistance()) } if entity.GetPoisonResistance() != 40 { t.Errorf("Expected poison resistance 40, got %d", entity.GetPoisonResistance()) } } func TestEntityMaintainedSpells(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() // Set max concentration info.SetMaxConcentration(10) // Test adding maintained spell success := entity.AddMaintainedSpell("Test Spell", 123, 60.0, 3) if !success { t.Error("Expected AddMaintainedSpell to succeed") } // Check concentration usage if info.GetCurConcentration() != 3 { t.Errorf("Expected current concentration 3, got %d", info.GetCurConcentration()) } // Test getting maintained spell effect := entity.GetMaintainedSpell(123) if effect == nil { t.Error("Expected to find maintained spell effect") } // Test adding spell that would exceed concentration success = entity.AddMaintainedSpell("Another Spell", 124, 60.0, 8) if success { t.Error("Expected AddMaintainedSpell to fail when concentration exceeded") } // Test removing maintained spell success = entity.RemoveMaintainedSpell(123) if !success { t.Error("Expected RemoveMaintainedSpell to succeed") } // Check concentration was returned if info.GetCurConcentration() != 0 { t.Errorf("Expected current concentration 0, got %d", info.GetCurConcentration()) } // Test removing non-existent spell success = entity.RemoveMaintainedSpell(999) if success { t.Error("Expected RemoveMaintainedSpell to fail for non-existent spell") } } func TestEntitySpellEffects(t *testing.T) { entity := NewEntity() // Test adding spell effect success := entity.AddSpellEffect(456, 789, 30.0) if !success { t.Error("Expected AddSpellEffect to succeed") } // Test removing spell effect success = entity.RemoveSpellEffect(456) if !success { t.Error("Expected RemoveSpellEffect to succeed") } // Test removing non-existent spell effect success = entity.RemoveSpellEffect(999) if success { t.Error("Expected RemoveSpellEffect to fail for non-existent spell") } } func TestEntityDetrimentalSpells(t *testing.T) { entity := NewEntity() // Test adding detrimental spell entity.AddDetrimentalSpell(789, 456, 45.0, 1) // Test getting detrimental effect effect := entity.GetDetrimentalEffect(789, 456) if effect == nil { t.Error("Expected to find detrimental spell effect") } // Test removing detrimental spell success := entity.RemoveDetrimentalSpell(789, 456) if !success { t.Error("Expected RemoveDetrimentalSpell to succeed") } // Test removing non-existent detrimental spell success = entity.RemoveDetrimentalSpell(999, 888) if success { t.Error("Expected RemoveDetrimentalSpell to fail for non-existent spell") } } func TestEntityBonusSystem(t *testing.T) { entity := NewEntity() // Test adding skill bonus entity.AddSkillBonus(123, 5, 15.0) // Skill ID 5, value 15.0 // Test adding stat bonus entity.AddStatBonus(124, 1, 5.0) // Stat type 1 (STR), value 5.0 // Test calculating bonuses entity.CalculateBonuses() // The actual bonus calculation depends on the spell effect manager implementation // We just test that the method doesn't panic } func TestEntityPetManagement(t *testing.T) { entity := NewEntity() pet := NewEntity() // Test setting and getting summon pet entity.SetPet(pet) if entity.GetPet() != pet { t.Error("Expected pet to be set correctly") } if pet.GetOwner() != entity.GetID() { t.Error("Expected pet owner to be set correctly") } if pet.GetPetType() != PetTypeSummon { t.Error("Expected pet type to be summon") } // Test charmed pet charmedPet := NewEntity() entity.SetCharmedPet(charmedPet) if entity.GetCharmedPet() != charmedPet { t.Error("Expected charmed pet to be set correctly") } if charmedPet.GetPetType() != PetTypeCharm { t.Error("Expected pet type to be charm") } // Test deity pet deityPet := NewEntity() entity.SetDeityPet(deityPet) if entity.GetDeityPet() != deityPet { t.Error("Expected deity pet to be set correctly") } if deityPet.GetPetType() != PetTypeDeity { t.Error("Expected pet type to be deity") } // Test cosmetic pet cosmeticPet := NewEntity() entity.SetCosmeticPet(cosmeticPet) if entity.GetCosmeticPet() != cosmeticPet { t.Error("Expected cosmetic pet to be set correctly") } if cosmeticPet.GetPetType() != PetTypeCosmetic { t.Error("Expected pet type to be cosmetic") } // Test pet dismissing state entity.SetPetDismissing(true) if !entity.IsPetDismissing() { t.Error("Expected pet to be dismissing") } entity.SetPetDismissing(false) if entity.IsPetDismissing() { t.Error("Expected pet to not be dismissing") } } func TestEntityDeity(t *testing.T) { entity := NewEntity() // Test setting and getting deity entity.SetDeity(5) if entity.GetDeity() != 5 { t.Errorf("Expected deity 5, got %d", entity.GetDeity()) } } func TestEntityDodgeChance(t *testing.T) { entity := NewEntity() // Test base dodge chance dodgeChance := entity.GetDodgeChance() if dodgeChance != 5.0 { t.Errorf("Expected base dodge chance 5.0, got %f", dodgeChance) } } func TestEntitySeeSpells(t *testing.T) { entity := NewEntity() // Test see invisible spell entity.SetSeeInvisSpell(true) if !entity.HasSeeInvisSpell() { t.Error("Expected entity to have see invisible spell") } entity.SetSeeInvisSpell(false) if entity.HasSeeInvisSpell() { t.Error("Expected entity to not have see invisible spell") } // Test see hidden spell entity.SetSeeHideSpell(true) if !entity.HasSeeHideSpell() { t.Error("Expected entity to have see hidden spell") } entity.SetSeeHideSpell(false) if entity.HasSeeHideSpell() { t.Error("Expected entity to not have see hidden spell") } } func TestEntityCleanupMethods(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() // Set up some spell effects and concentration usage info.SetMaxConcentration(10) entity.AddMaintainedSpell("Test Spell 1", 123, 60.0, 3) entity.AddMaintainedSpell("Test Spell 2", 124, 60.0, 2) entity.AddSpellEffect(456, 789, 30.0) // Verify concentration is used if info.GetCurConcentration() != 5 { t.Errorf("Expected current concentration 5, got %d", info.GetCurConcentration()) } // Test deleting all spell effects entity.DeleteSpellEffects(false) // Verify concentration was returned if info.GetCurConcentration() != 0 { t.Errorf("Expected current concentration 0 after cleanup, got %d", info.GetCurConcentration()) } // Test RemoveSpells entity.AddMaintainedSpell("Test Spell 3", 125, 60.0, 2) entity.RemoveSpells(false) // Remove all spells if info.GetCurConcentration() != 0 { t.Errorf("Expected current concentration 0 after RemoveSpells, got %d", info.GetCurConcentration()) } } func TestEntityProcessEffects(t *testing.T) { entity := NewEntity() // Test that ProcessEffects doesn't panic entity.ProcessEffects() } func TestEntityClassSystemIntegration(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() // Test class getter/setter info.SetClass1(5) if entity.GetClass() != 5 { t.Errorf("Expected class 5, got %d", entity.GetClass()) } entity.SetClass(10) if entity.GetClass() != 10 { t.Errorf("Expected class 10, got %d", entity.GetClass()) } // Test level getter info.SetLevel(25) if entity.GetLevel() != 25 { t.Errorf("Expected level 25, got %d", entity.GetLevel()) } } func TestEntityConcurrency(t *testing.T) { entity := NewEntity() info := entity.GetInfoStruct() info.SetMaxConcentration(20) var wg sync.WaitGroup numGoroutines := 10 // Test concurrent access to combat state wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() entity.SetInCombat(true) _ = entity.IsInCombat() entity.SetInCombat(false) }() } wg.Wait() // Test concurrent access to casting state wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() entity.SetCasting(true) _ = entity.IsCasting() entity.SetCasting(false) }() } wg.Wait() // Test concurrent spell effect operations wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { spellID := int32(1000 + i) go func(id int32) { defer wg.Done() entity.AddSpellEffect(id, 123, 30.0) time.Sleep(time.Millisecond) // Small delay to ensure some overlap entity.RemoveSpellEffect(id) }(spellID) } wg.Wait() // Test concurrent maintained spell operations wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { spellID := int32(2000 + i) go func(id int32) { defer wg.Done() if entity.AddMaintainedSpell("Concurrent Spell", id, 60.0, 1) { time.Sleep(time.Millisecond) entity.RemoveMaintainedSpell(id) } }(spellID) } wg.Wait() } func TestEntityControlEffects(t *testing.T) { entity := NewEntity() // Test has control effect - should work without panicking // The actual implementation depends on the spell effect manager hasStun := entity.HasControlEffect(ControlEffectStun) _ = hasStun // We can't easily test the actual value without setting up effects } func TestEntityConstants(t *testing.T) { // Test pet type constants if PetTypeSummon != 1 { t.Errorf("Expected PetTypeSummon to be 1, got %d", PetTypeSummon) } if PetTypeCharm != 2 { t.Errorf("Expected PetTypeCharm to be 2, got %d", PetTypeCharm) } if PetTypeDeity != 3 { t.Errorf("Expected PetTypeDeity to be 3, got %d", PetTypeDeity) } if PetTypeCosmetic != 4 { t.Errorf("Expected PetTypeCosmetic to be 4, got %d", PetTypeCosmetic) } // Test control effect constants (re-exported from spells package) if ControlEffectStun == 0 && ControlEffectRoot == 0 { t.Error("Control effect constants should be non-zero") } }