eq2go/internal/entity/entity_test.go

657 lines
16 KiB
Go

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")
}
}