1624 lines
42 KiB
Go
1624 lines
42 KiB
Go
package ai
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Mock implementations for testing
|
|
|
|
// MockNPC provides a mock NPC implementation for testing
|
|
type MockNPC struct {
|
|
id int32
|
|
name string
|
|
hp int32
|
|
totalHP int32
|
|
inCombat bool
|
|
target Entity
|
|
isPet bool
|
|
owner Entity
|
|
x, y, z float32
|
|
distance float32
|
|
following bool
|
|
followTarget Spawn
|
|
runningBack bool
|
|
mezzedOrStunned bool
|
|
casting bool
|
|
dazed bool
|
|
feared bool
|
|
stifled bool
|
|
inWater bool
|
|
waterCreature bool
|
|
flyingCreature bool
|
|
attackAllowed bool
|
|
primaryWeaponReady bool
|
|
secondaryWeaponReady bool
|
|
castPercentage int8
|
|
nextSpell Spell
|
|
nextBuffSpell Spell
|
|
checkLoS bool
|
|
pauseMovementTimer bool
|
|
runbackLocation *MovementLocation
|
|
runbackDistance float32
|
|
shouldCallRunback bool
|
|
spawnScript string
|
|
}
|
|
|
|
func NewMockNPC(id int32, name string) *MockNPC {
|
|
return &MockNPC{
|
|
id: id,
|
|
name: name,
|
|
hp: 100,
|
|
totalHP: 100,
|
|
inCombat: false,
|
|
isPet: false,
|
|
x: 0,
|
|
y: 0,
|
|
z: 0,
|
|
distance: 10.0,
|
|
following: false,
|
|
runningBack: false,
|
|
mezzedOrStunned: false,
|
|
casting: false,
|
|
dazed: false,
|
|
feared: false,
|
|
stifled: false,
|
|
inWater: false,
|
|
waterCreature: false,
|
|
flyingCreature: false,
|
|
attackAllowed: true,
|
|
primaryWeaponReady: true,
|
|
secondaryWeaponReady: true,
|
|
castPercentage: 25,
|
|
checkLoS: true,
|
|
pauseMovementTimer: false,
|
|
runbackDistance: 0,
|
|
shouldCallRunback: false,
|
|
spawnScript: "",
|
|
}
|
|
}
|
|
|
|
// Implement NPC interface
|
|
func (m *MockNPC) GetID() int32 { return m.id }
|
|
func (m *MockNPC) GetName() string { return m.name }
|
|
func (m *MockNPC) GetHP() int32 { return m.hp }
|
|
func (m *MockNPC) GetTotalHP() int32 { return m.totalHP }
|
|
func (m *MockNPC) SetHP(hp int32) { m.hp = hp }
|
|
func (m *MockNPC) IsAlive() bool { return m.hp > 0 }
|
|
func (m *MockNPC) GetInCombat() bool { return m.inCombat }
|
|
func (m *MockNPC) InCombat(val bool) { m.inCombat = val }
|
|
func (m *MockNPC) GetTarget() Entity { return m.target }
|
|
func (m *MockNPC) SetTarget(target Entity) { m.target = target }
|
|
func (m *MockNPC) IsPet() bool { return m.isPet }
|
|
func (m *MockNPC) GetOwner() Entity { return m.owner }
|
|
func (m *MockNPC) GetX() float32 { return m.x }
|
|
func (m *MockNPC) GetY() float32 { return m.y }
|
|
func (m *MockNPC) GetZ() float32 { return m.z }
|
|
func (m *MockNPC) GetDistance(target Entity) float32 { return m.distance }
|
|
func (m *MockNPC) FaceTarget(target Entity, followCaller bool) {}
|
|
func (m *MockNPC) IsFollowing() bool { return m.following }
|
|
func (m *MockNPC) SetFollowing(val bool) { m.following = val }
|
|
func (m *MockNPC) GetFollowTarget() Spawn { return m.followTarget }
|
|
func (m *MockNPC) SetFollowTarget(target Spawn, range_ float32) { m.followTarget = target }
|
|
func (m *MockNPC) CalculateRunningLocation(clear bool) {}
|
|
func (m *MockNPC) ClearRunningLocations() {}
|
|
func (m *MockNPC) IsRunningBack() bool { return m.runningBack }
|
|
func (m *MockNPC) GetRunbackLocation() *MovementLocation { return m.runbackLocation }
|
|
func (m *MockNPC) GetRunbackDistance() float32 { return m.runbackDistance }
|
|
func (m *MockNPC) Runback(distance float32) { m.runningBack = true }
|
|
func (m *MockNPC) ShouldCallRunback() bool { return m.shouldCallRunback }
|
|
func (m *MockNPC) SetCallRunback(val bool) { m.shouldCallRunback = val }
|
|
func (m *MockNPC) IsMezzedOrStunned() bool { return m.mezzedOrStunned }
|
|
func (m *MockNPC) IsCasting() bool { return m.casting }
|
|
func (m *MockNPC) IsDazed() bool { return m.dazed }
|
|
func (m *MockNPC) IsFeared() bool { return m.feared }
|
|
func (m *MockNPC) IsStifled() bool { return m.stifled }
|
|
func (m *MockNPC) InWater() bool { return m.inWater }
|
|
func (m *MockNPC) IsWaterCreature() bool { return m.waterCreature }
|
|
func (m *MockNPC) IsFlyingCreature() bool { return m.flyingCreature }
|
|
func (m *MockNPC) AttackAllowed(target Entity) bool { return m.attackAllowed }
|
|
func (m *MockNPC) PrimaryWeaponReady() bool { return m.primaryWeaponReady }
|
|
func (m *MockNPC) SecondaryWeaponReady() bool { return m.secondaryWeaponReady }
|
|
func (m *MockNPC) SetPrimaryLastAttackTime(time int64) {}
|
|
func (m *MockNPC) SetSecondaryLastAttackTime(time int64) {}
|
|
func (m *MockNPC) MeleeAttack(target Entity, distance float32, primary bool) {}
|
|
func (m *MockNPC) GetCastPercentage() int8 { return m.castPercentage }
|
|
func (m *MockNPC) GetNextSpell(target Entity, distance float32) Spell { return m.nextSpell }
|
|
func (m *MockNPC) GetNextBuffSpell(target Spawn) Spell { return m.nextBuffSpell }
|
|
func (m *MockNPC) SetCastOnAggroCompleted(val bool) {}
|
|
func (m *MockNPC) CheckLoS(target Entity) bool { return m.checkLoS }
|
|
func (m *MockNPC) IsPauseMovementTimerActive() bool { return m.pauseMovementTimer }
|
|
func (m *MockNPC) SetEncounterState(state int8) {}
|
|
func (m *MockNPC) GetSpawnScript() string { return m.spawnScript }
|
|
func (m *MockNPC) KillSpawn(npc NPC) {}
|
|
|
|
// Implement Entity interface (extends Spawn)
|
|
func (m *MockNPC) IsPlayer() bool { return false }
|
|
func (m *MockNPC) IsBot() bool { return false }
|
|
|
|
// MockEntity provides a mock Entity implementation for testing
|
|
type MockEntity struct {
|
|
id int32
|
|
name string
|
|
hp int32
|
|
totalHP int32
|
|
x, y, z float32
|
|
isPlayer bool
|
|
isBot bool
|
|
isPet bool
|
|
owner Entity
|
|
inWater bool
|
|
}
|
|
|
|
func NewMockEntity(id int32, name string) *MockEntity {
|
|
return &MockEntity{
|
|
id: id,
|
|
name: name,
|
|
hp: 100,
|
|
totalHP: 100,
|
|
x: 0,
|
|
y: 0,
|
|
z: 0,
|
|
isPlayer: false,
|
|
isBot: false,
|
|
isPet: false,
|
|
inWater: false,
|
|
}
|
|
}
|
|
|
|
func (m *MockEntity) GetID() int32 { return m.id }
|
|
func (m *MockEntity) GetName() string { return m.name }
|
|
func (m *MockEntity) GetHP() int32 { return m.hp }
|
|
func (m *MockEntity) GetTotalHP() int32 { return m.totalHP }
|
|
func (m *MockEntity) GetX() float32 { return m.x }
|
|
func (m *MockEntity) GetY() float32 { return m.y }
|
|
func (m *MockEntity) GetZ() float32 { return m.z }
|
|
func (m *MockEntity) IsPlayer() bool { return m.isPlayer }
|
|
func (m *MockEntity) IsBot() bool { return m.isBot }
|
|
func (m *MockEntity) IsPet() bool { return m.isPet }
|
|
func (m *MockEntity) GetOwner() Entity { return m.owner }
|
|
func (m *MockEntity) InWater() bool { return m.inWater }
|
|
|
|
// MockSpell provides a mock Spell implementation for testing
|
|
type MockSpell struct {
|
|
id int32
|
|
name string
|
|
friendly bool
|
|
castTime int32
|
|
recoveryTime int32
|
|
range_ float32
|
|
minRange float32
|
|
}
|
|
|
|
func NewMockSpell(id int32, name string) *MockSpell {
|
|
return &MockSpell{
|
|
id: id,
|
|
name: name,
|
|
friendly: false,
|
|
castTime: 1000,
|
|
recoveryTime: 2000,
|
|
range_: 30.0,
|
|
minRange: 0.0,
|
|
}
|
|
}
|
|
|
|
func (m *MockSpell) GetSpellID() int32 { return m.id }
|
|
func (m *MockSpell) GetName() string { return m.name }
|
|
func (m *MockSpell) IsFriendlySpell() bool { return m.friendly }
|
|
func (m *MockSpell) GetCastTime() int32 { return m.castTime }
|
|
func (m *MockSpell) GetRecoveryTime() int32 { return m.recoveryTime }
|
|
func (m *MockSpell) GetRange() float32 { return m.range_ }
|
|
func (m *MockSpell) GetMinRange() float32 { return m.minRange }
|
|
|
|
// MockLogger provides a mock Logger implementation for testing
|
|
type MockLogger struct {
|
|
messages []string
|
|
}
|
|
|
|
func NewMockLogger() *MockLogger {
|
|
return &MockLogger{
|
|
messages: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
func (m *MockLogger) LogInfo(message string, args ...any) {
|
|
m.messages = append(m.messages, "INFO: "+message)
|
|
}
|
|
|
|
func (m *MockLogger) LogError(message string, args ...any) {
|
|
m.messages = append(m.messages, "ERROR: "+message)
|
|
}
|
|
|
|
func (m *MockLogger) LogDebug(message string, args ...any) {
|
|
m.messages = append(m.messages, "DEBUG: "+message)
|
|
}
|
|
|
|
func (m *MockLogger) LogWarning(message string, args ...any) {
|
|
m.messages = append(m.messages, "WARNING: "+message)
|
|
}
|
|
|
|
func (m *MockLogger) GetMessages() []string {
|
|
return m.messages
|
|
}
|
|
|
|
// MockLuaInterface provides a mock LuaInterface implementation for testing
|
|
type MockLuaInterface struct {
|
|
executed bool
|
|
lastScript string
|
|
lastFunction string
|
|
shouldError bool
|
|
}
|
|
|
|
func NewMockLuaInterface() *MockLuaInterface {
|
|
return &MockLuaInterface{
|
|
executed: false,
|
|
shouldError: false,
|
|
}
|
|
}
|
|
|
|
func (m *MockLuaInterface) RunSpawnScript(script, function string, npc NPC, target Entity) error {
|
|
m.executed = true
|
|
m.lastScript = script
|
|
m.lastFunction = function
|
|
|
|
if m.shouldError {
|
|
return fmt.Errorf("mock lua error")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *MockLuaInterface) WasExecuted() bool {
|
|
return m.executed
|
|
}
|
|
|
|
func (m *MockLuaInterface) SetShouldError(shouldError bool) {
|
|
m.shouldError = shouldError
|
|
}
|
|
|
|
// Tests for HateEntry and HateList
|
|
|
|
func TestNewHateEntry(t *testing.T) {
|
|
entityID := int32(123)
|
|
hateValue := int32(500)
|
|
|
|
entry := NewHateEntry(entityID, hateValue)
|
|
|
|
if entry.EntityID != entityID {
|
|
t.Errorf("Expected entity ID %d, got %d", entityID, entry.EntityID)
|
|
}
|
|
|
|
if entry.HateValue != hateValue {
|
|
t.Errorf("Expected hate value %d, got %d", hateValue, entry.HateValue)
|
|
}
|
|
|
|
if entry.LastUpdated == 0 {
|
|
t.Error("Expected LastUpdated to be set")
|
|
}
|
|
}
|
|
|
|
func TestNewHateEntryMinValue(t *testing.T) {
|
|
entityID := int32(123)
|
|
hateValue := int32(0) // Below minimum
|
|
|
|
entry := NewHateEntry(entityID, hateValue)
|
|
|
|
if entry.HateValue != MinHateValue {
|
|
t.Errorf("Expected hate value to be adjusted to minimum %d, got %d", MinHateValue, entry.HateValue)
|
|
}
|
|
}
|
|
|
|
func TestNewHateList(t *testing.T) {
|
|
hateList := NewHateList()
|
|
|
|
if hateList == nil {
|
|
t.Fatal("NewHateList returned nil")
|
|
}
|
|
|
|
if hateList.Size() != 0 {
|
|
t.Errorf("Expected empty hate list, got size %d", hateList.Size())
|
|
}
|
|
}
|
|
|
|
func TestHateListAddHate(t *testing.T) {
|
|
hateList := NewHateList()
|
|
entityID := int32(123)
|
|
hateValue := int32(500)
|
|
|
|
hateList.AddHate(entityID, hateValue)
|
|
|
|
if hateList.Size() != 1 {
|
|
t.Errorf("Expected hate list size 1, got %d", hateList.Size())
|
|
}
|
|
|
|
retrievedHate := hateList.GetHate(entityID)
|
|
if retrievedHate != hateValue {
|
|
t.Errorf("Expected hate value %d, got %d", hateValue, retrievedHate)
|
|
}
|
|
}
|
|
|
|
func TestHateListAddHateUpdate(t *testing.T) {
|
|
hateList := NewHateList()
|
|
entityID := int32(123)
|
|
initialHate := int32(500)
|
|
additionalHate := int32(200)
|
|
|
|
hateList.AddHate(entityID, initialHate)
|
|
hateList.AddHate(entityID, additionalHate)
|
|
|
|
if hateList.Size() != 1 {
|
|
t.Errorf("Expected hate list size 1, got %d", hateList.Size())
|
|
}
|
|
|
|
expectedTotal := initialHate + additionalHate
|
|
retrievedHate := hateList.GetHate(entityID)
|
|
if retrievedHate != expectedTotal {
|
|
t.Errorf("Expected hate value %d, got %d", expectedTotal, retrievedHate)
|
|
}
|
|
}
|
|
|
|
func TestHateListGetMostHated(t *testing.T) {
|
|
hateList := NewHateList()
|
|
|
|
entity1 := int32(1)
|
|
entity2 := int32(2)
|
|
entity3 := int32(3)
|
|
|
|
hateList.AddHate(entity1, 100)
|
|
hateList.AddHate(entity2, 500) // Highest hate
|
|
hateList.AddHate(entity3, 200)
|
|
|
|
mostHated := hateList.GetMostHated()
|
|
if mostHated != entity2 {
|
|
t.Errorf("Expected most hated entity %d, got %d", entity2, mostHated)
|
|
}
|
|
}
|
|
|
|
func TestHateListGetHatePercentage(t *testing.T) {
|
|
hateList := NewHateList()
|
|
|
|
entity1 := int32(1)
|
|
entity2 := int32(2)
|
|
|
|
hateList.AddHate(entity1, 300) // 75% of total hate (300/400)
|
|
hateList.AddHate(entity2, 100) // 25% of total hate (100/400)
|
|
|
|
percentage1 := hateList.GetHatePercentage(entity1)
|
|
percentage2 := hateList.GetHatePercentage(entity2)
|
|
|
|
if percentage1 != 75 {
|
|
t.Errorf("Expected entity1 hate percentage 75, got %d", percentage1)
|
|
}
|
|
|
|
if percentage2 != 25 {
|
|
t.Errorf("Expected entity2 hate percentage 25, got %d", percentage2)
|
|
}
|
|
}
|
|
|
|
func TestHateListRemoveHate(t *testing.T) {
|
|
hateList := NewHateList()
|
|
entityID := int32(123)
|
|
|
|
hateList.AddHate(entityID, 500)
|
|
hateList.RemoveHate(entityID)
|
|
|
|
if hateList.Size() != 0 {
|
|
t.Errorf("Expected empty hate list after removal, got size %d", hateList.Size())
|
|
}
|
|
|
|
retrievedHate := hateList.GetHate(entityID)
|
|
if retrievedHate != 0 {
|
|
t.Errorf("Expected hate value 0 after removal, got %d", retrievedHate)
|
|
}
|
|
}
|
|
|
|
func TestHateListClear(t *testing.T) {
|
|
hateList := NewHateList()
|
|
|
|
hateList.AddHate(1, 100)
|
|
hateList.AddHate(2, 200)
|
|
hateList.AddHate(3, 300)
|
|
|
|
hateList.Clear()
|
|
|
|
if hateList.Size() != 0 {
|
|
t.Errorf("Expected empty hate list after clear, got size %d", hateList.Size())
|
|
}
|
|
}
|
|
|
|
func TestHateListGetAllEntries(t *testing.T) {
|
|
hateList := NewHateList()
|
|
|
|
entity1 := int32(1)
|
|
entity2 := int32(2)
|
|
hate1 := int32(100)
|
|
hate2 := int32(200)
|
|
|
|
hateList.AddHate(entity1, hate1)
|
|
hateList.AddHate(entity2, hate2)
|
|
|
|
entries := hateList.GetAllEntries()
|
|
|
|
if len(entries) != 2 {
|
|
t.Errorf("Expected 2 entries, got %d", len(entries))
|
|
}
|
|
|
|
if entries[entity1].HateValue != hate1 {
|
|
t.Errorf("Expected entity1 hate %d, got %d", hate1, entries[entity1].HateValue)
|
|
}
|
|
|
|
if entries[entity2].HateValue != hate2 {
|
|
t.Errorf("Expected entity2 hate %d, got %d", hate2, entries[entity2].HateValue)
|
|
}
|
|
}
|
|
|
|
// Tests for EncounterEntry and EncounterList
|
|
|
|
func TestNewEncounterEntry(t *testing.T) {
|
|
entityID := int32(123)
|
|
characterID := int32(456)
|
|
isPlayer := true
|
|
isBot := false
|
|
|
|
entry := NewEncounterEntry(entityID, characterID, isPlayer, isBot)
|
|
|
|
if entry.EntityID != entityID {
|
|
t.Errorf("Expected entity ID %d, got %d", entityID, entry.EntityID)
|
|
}
|
|
|
|
if entry.CharacterID != characterID {
|
|
t.Errorf("Expected character ID %d, got %d", characterID, entry.CharacterID)
|
|
}
|
|
|
|
if entry.IsPlayer != isPlayer {
|
|
t.Errorf("Expected IsPlayer %v, got %v", isPlayer, entry.IsPlayer)
|
|
}
|
|
|
|
if entry.IsBot != isBot {
|
|
t.Errorf("Expected IsBot %v, got %v", isBot, entry.IsBot)
|
|
}
|
|
|
|
if entry.AddedTime == 0 {
|
|
t.Error("Expected AddedTime to be set")
|
|
}
|
|
}
|
|
|
|
func TestNewEncounterList(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
|
|
if encounterList == nil {
|
|
t.Fatal("NewEncounterList returned nil")
|
|
}
|
|
|
|
if encounterList.Size() != 0 {
|
|
t.Errorf("Expected empty encounter list, got size %d", encounterList.Size())
|
|
}
|
|
|
|
if encounterList.HasPlayerInEncounter() {
|
|
t.Error("Expected no players in encounter initially")
|
|
}
|
|
}
|
|
|
|
func TestEncounterListAddEntity(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
entityID := int32(123)
|
|
characterID := int32(456)
|
|
|
|
success := encounterList.AddEntity(entityID, characterID, true, false)
|
|
|
|
if !success {
|
|
t.Error("Expected AddEntity to succeed")
|
|
}
|
|
|
|
if encounterList.Size() != 1 {
|
|
t.Errorf("Expected encounter list size 1, got %d", encounterList.Size())
|
|
}
|
|
|
|
if !encounterList.IsEntityInEncounter(entityID) {
|
|
t.Error("Entity should be in encounter")
|
|
}
|
|
|
|
if !encounterList.IsPlayerInEncounter(characterID) {
|
|
t.Error("Player should be in encounter")
|
|
}
|
|
|
|
if !encounterList.HasPlayerInEncounter() {
|
|
t.Error("Should have player in encounter")
|
|
}
|
|
}
|
|
|
|
func TestEncounterListAddEntityDuplicate(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
entityID := int32(123)
|
|
|
|
success1 := encounterList.AddEntity(entityID, 0, false, false)
|
|
success2 := encounterList.AddEntity(entityID, 0, false, false) // Duplicate
|
|
|
|
if !success1 {
|
|
t.Error("Expected first AddEntity to succeed")
|
|
}
|
|
|
|
if success2 {
|
|
t.Error("Expected second AddEntity to fail (duplicate)")
|
|
}
|
|
|
|
if encounterList.Size() != 1 {
|
|
t.Errorf("Expected encounter list size 1 after duplicate add, got %d", encounterList.Size())
|
|
}
|
|
}
|
|
|
|
func TestEncounterListRemoveEntity(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
entityID := int32(123)
|
|
characterID := int32(456)
|
|
|
|
encounterList.AddEntity(entityID, characterID, true, false)
|
|
encounterList.RemoveEntity(entityID)
|
|
|
|
if encounterList.Size() != 0 {
|
|
t.Errorf("Expected empty encounter list after removal, got size %d", encounterList.Size())
|
|
}
|
|
|
|
if encounterList.IsEntityInEncounter(entityID) {
|
|
t.Error("Entity should not be in encounter after removal")
|
|
}
|
|
|
|
if encounterList.IsPlayerInEncounter(characterID) {
|
|
t.Error("Player should not be in encounter after removal")
|
|
}
|
|
|
|
if encounterList.HasPlayerInEncounter() {
|
|
t.Error("Should not have player in encounter after removal")
|
|
}
|
|
}
|
|
|
|
func TestEncounterListCountPlayerBots(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
|
|
encounterList.AddEntity(1, 101, true, false) // Player
|
|
encounterList.AddEntity(2, 0, false, true) // Bot
|
|
encounterList.AddEntity(3, 0, false, false) // NPC
|
|
|
|
count := encounterList.CountPlayerBots()
|
|
if count != 2 {
|
|
t.Errorf("Expected 2 players/bots, got %d", count)
|
|
}
|
|
}
|
|
|
|
func TestEncounterListGetAllEntityIDs(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
|
|
entity1 := int32(1)
|
|
entity2 := int32(2)
|
|
entity3 := int32(3)
|
|
|
|
encounterList.AddEntity(entity1, 0, false, false)
|
|
encounterList.AddEntity(entity2, 0, false, false)
|
|
encounterList.AddEntity(entity3, 0, false, false)
|
|
|
|
entityIDs := encounterList.GetAllEntityIDs()
|
|
|
|
if len(entityIDs) != 3 {
|
|
t.Errorf("Expected 3 entity IDs, got %d", len(entityIDs))
|
|
}
|
|
|
|
// Check that all IDs are present (order doesn't matter)
|
|
idMap := make(map[int32]bool)
|
|
for _, id := range entityIDs {
|
|
idMap[id] = true
|
|
}
|
|
|
|
if !idMap[entity1] || !idMap[entity2] || !idMap[entity3] {
|
|
t.Error("Expected all entity IDs to be present")
|
|
}
|
|
}
|
|
|
|
func TestEncounterListClear(t *testing.T) {
|
|
encounterList := NewEncounterList()
|
|
|
|
encounterList.AddEntity(1, 101, true, false)
|
|
encounterList.AddEntity(2, 0, false, false)
|
|
|
|
encounterList.Clear()
|
|
|
|
if encounterList.Size() != 0 {
|
|
t.Errorf("Expected empty encounter list after clear, got size %d", encounterList.Size())
|
|
}
|
|
|
|
if encounterList.HasPlayerInEncounter() {
|
|
t.Error("Should not have player in encounter after clear")
|
|
}
|
|
}
|
|
|
|
// Tests for BrainState
|
|
|
|
func TestNewBrainState(t *testing.T) {
|
|
state := NewBrainState()
|
|
|
|
if state == nil {
|
|
t.Fatal("NewBrainState returned nil")
|
|
}
|
|
|
|
if state.GetState() != AIStateIdle {
|
|
t.Errorf("Expected initial state %d, got %d", AIStateIdle, state.GetState())
|
|
}
|
|
|
|
if !state.IsActive() {
|
|
t.Error("Expected brain state to be active initially")
|
|
}
|
|
|
|
if state.GetThinkTick() != DefaultThinkTick {
|
|
t.Errorf("Expected think tick %d, got %d", DefaultThinkTick, state.GetThinkTick())
|
|
}
|
|
|
|
if state.GetDebugLevel() != DebugLevelNone {
|
|
t.Errorf("Expected debug level %d, got %d", DebugLevelNone, state.GetDebugLevel())
|
|
}
|
|
}
|
|
|
|
func TestBrainStateSetState(t *testing.T) {
|
|
state := NewBrainState()
|
|
newState := AIStateCombat
|
|
|
|
state.SetState(newState)
|
|
|
|
if state.GetState() != newState {
|
|
t.Errorf("Expected state %d, got %d", newState, state.GetState())
|
|
}
|
|
}
|
|
|
|
func TestBrainStateSetActive(t *testing.T) {
|
|
state := NewBrainState()
|
|
|
|
state.SetActive(false)
|
|
if state.IsActive() {
|
|
t.Error("Expected brain state to be inactive")
|
|
}
|
|
|
|
state.SetActive(true)
|
|
if !state.IsActive() {
|
|
t.Error("Expected brain state to be active")
|
|
}
|
|
}
|
|
|
|
func TestBrainStateSetThinkTick(t *testing.T) {
|
|
state := NewBrainState()
|
|
|
|
// Test normal value
|
|
newTick := int32(500)
|
|
state.SetThinkTick(newTick)
|
|
if state.GetThinkTick() != newTick {
|
|
t.Errorf("Expected think tick %d, got %d", newTick, state.GetThinkTick())
|
|
}
|
|
|
|
// Test minimum value
|
|
state.SetThinkTick(0)
|
|
if state.GetThinkTick() != 1 {
|
|
t.Errorf("Expected think tick to be adjusted to minimum 1, got %d", state.GetThinkTick())
|
|
}
|
|
|
|
// Test maximum value
|
|
state.SetThinkTick(MaxThinkTick + 1000)
|
|
if state.GetThinkTick() != MaxThinkTick {
|
|
t.Errorf("Expected think tick to be adjusted to maximum %d, got %d", MaxThinkTick, state.GetThinkTick())
|
|
}
|
|
}
|
|
|
|
func TestBrainStateSetLastThink(t *testing.T) {
|
|
state := NewBrainState()
|
|
timestamp := time.Now().UnixMilli()
|
|
|
|
state.SetLastThink(timestamp)
|
|
|
|
if state.GetLastThink() != timestamp {
|
|
t.Errorf("Expected last think timestamp %d, got %d", timestamp, state.GetLastThink())
|
|
}
|
|
}
|
|
|
|
func TestBrainStateSpellRecovery(t *testing.T) {
|
|
state := NewBrainState()
|
|
|
|
// Test future recovery time
|
|
futureTime := time.Now().UnixMilli() + 5000
|
|
state.SetSpellRecovery(futureTime)
|
|
|
|
if state.GetSpellRecovery() != futureTime {
|
|
t.Errorf("Expected spell recovery time %d, got %d", futureTime, state.GetSpellRecovery())
|
|
}
|
|
|
|
if state.HasRecovered() {
|
|
t.Error("Expected brain to not have recovered yet")
|
|
}
|
|
|
|
// Test past recovery time
|
|
pastTime := time.Now().UnixMilli() - 5000
|
|
state.SetSpellRecovery(pastTime)
|
|
|
|
if !state.HasRecovered() {
|
|
t.Error("Expected brain to have recovered")
|
|
}
|
|
}
|
|
|
|
func TestBrainStateDebugLevel(t *testing.T) {
|
|
state := NewBrainState()
|
|
debugLevel := DebugLevelVerbose
|
|
|
|
state.SetDebugLevel(debugLevel)
|
|
|
|
if state.GetDebugLevel() != debugLevel {
|
|
t.Errorf("Expected debug level %d, got %d", debugLevel, state.GetDebugLevel())
|
|
}
|
|
}
|
|
|
|
// Tests for BrainStatistics
|
|
|
|
func TestNewBrainStatistics(t *testing.T) {
|
|
stats := NewBrainStatistics()
|
|
|
|
if stats == nil {
|
|
t.Fatal("NewBrainStatistics returned nil")
|
|
}
|
|
|
|
if stats.ThinkCycles != 0 {
|
|
t.Errorf("Expected think cycles 0, got %d", stats.ThinkCycles)
|
|
}
|
|
|
|
if stats.SpellsCast != 0 {
|
|
t.Errorf("Expected spells cast 0, got %d", stats.SpellsCast)
|
|
}
|
|
|
|
if stats.MeleeAttacks != 0 {
|
|
t.Errorf("Expected melee attacks 0, got %d", stats.MeleeAttacks)
|
|
}
|
|
|
|
if stats.AverageThinkTime != 0.0 {
|
|
t.Errorf("Expected average think time 0.0, got %f", stats.AverageThinkTime)
|
|
}
|
|
|
|
if stats.LastThinkTime == 0 {
|
|
t.Error("Expected LastThinkTime to be set")
|
|
}
|
|
}
|
|
|
|
// Tests for BaseBrain
|
|
|
|
func TestNewBaseBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewBaseBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeDefault {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDefault, brain.GetBrainType())
|
|
}
|
|
|
|
if !brain.IsActive() {
|
|
t.Error("Expected brain to be active initially")
|
|
}
|
|
|
|
if brain.GetBody() != npc {
|
|
t.Error("Expected brain body to be the provided NPC")
|
|
}
|
|
}
|
|
|
|
func TestBaseBrainHateManagement(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
entityID := int32(456)
|
|
hateValue := int32(500)
|
|
|
|
// Add hate
|
|
brain.AddHate(entityID, hateValue)
|
|
|
|
if brain.GetHate(entityID) != hateValue {
|
|
t.Errorf("Expected hate value %d, got %d", hateValue, brain.GetHate(entityID))
|
|
}
|
|
|
|
if brain.GetMostHated() != entityID {
|
|
t.Errorf("Expected most hated entity %d, got %d", entityID, brain.GetMostHated())
|
|
}
|
|
|
|
// Clear hate for entity
|
|
brain.ClearHateForEntity(entityID)
|
|
|
|
if brain.GetHate(entityID) != 0 {
|
|
t.Errorf("Expected hate value 0 after clearing, got %d", brain.GetHate(entityID))
|
|
}
|
|
|
|
// Add hate again and clear all
|
|
brain.AddHate(entityID, hateValue)
|
|
brain.ClearHate()
|
|
|
|
if brain.GetHate(entityID) != 0 {
|
|
t.Errorf("Expected hate value 0 after clearing all, got %d", brain.GetHate(entityID))
|
|
}
|
|
}
|
|
|
|
func TestBaseBrainEncounterManagement(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
entityID := int32(456)
|
|
characterID := int32(789)
|
|
|
|
// Add to encounter
|
|
success := brain.AddToEncounter(entityID, characterID, true, false)
|
|
|
|
if !success {
|
|
t.Error("Expected AddToEncounter to succeed")
|
|
}
|
|
|
|
if !brain.IsEntityInEncounter(entityID) {
|
|
t.Error("Entity should be in encounter")
|
|
}
|
|
|
|
if !brain.IsPlayerInEncounter(characterID) {
|
|
t.Error("Player should be in encounter")
|
|
}
|
|
|
|
if !brain.HasPlayerInEncounter() {
|
|
t.Error("Should have player in encounter")
|
|
}
|
|
|
|
if brain.GetEncounterSize() != 1 {
|
|
t.Errorf("Expected encounter size 1, got %d", brain.GetEncounterSize())
|
|
}
|
|
|
|
// Check loot allowed
|
|
if !brain.CheckLootAllowed(entityID) {
|
|
t.Error("Loot should be allowed for entity in encounter")
|
|
}
|
|
|
|
// Clear encounter
|
|
brain.ClearEncounter()
|
|
|
|
if brain.IsEntityInEncounter(entityID) {
|
|
t.Error("Entity should not be in encounter after clear")
|
|
}
|
|
|
|
if brain.GetEncounterSize() != 0 {
|
|
t.Errorf("Expected encounter size 0 after clear, got %d", brain.GetEncounterSize())
|
|
}
|
|
}
|
|
|
|
func TestBaseBrainStatistics(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
// Get initial statistics
|
|
stats := brain.GetStatistics()
|
|
if stats == nil {
|
|
t.Fatal("GetStatistics returned nil")
|
|
}
|
|
|
|
// Reset statistics
|
|
brain.ResetStatistics()
|
|
|
|
// Get statistics again
|
|
newStats := brain.GetStatistics()
|
|
if newStats.ThinkCycles != 0 {
|
|
t.Errorf("Expected think cycles 0 after reset, got %d", newStats.ThinkCycles)
|
|
}
|
|
}
|
|
|
|
func TestBaseBrainSetBody(t *testing.T) {
|
|
npc1 := NewMockNPC(123, "TestNPC1")
|
|
npc2 := NewMockNPC(456, "TestNPC2")
|
|
logger := NewMockLogger()
|
|
brain := NewBaseBrain(npc1, logger)
|
|
|
|
if brain.GetBody() != npc1 {
|
|
t.Error("Expected brain body to be npc1 initially")
|
|
}
|
|
|
|
brain.SetBody(npc2)
|
|
|
|
if brain.GetBody() != npc2 {
|
|
t.Error("Expected brain body to be npc2 after SetBody")
|
|
}
|
|
}
|
|
|
|
// Tests for Brain Variants
|
|
|
|
func TestNewCombatPetBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
npc.isPet = true
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewCombatPetBrain(npc, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewCombatPetBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeCombatPet {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeCombatPet, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestNewNonCombatPetBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
npc.isPet = true
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewNonCombatPetBrain(npc, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewNonCombatPetBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeNonCombatPet {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeNonCombatPet, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestNewBlankBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewBlankBrain(npc, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewBlankBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeBlank {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeBlank, brain.GetBrainType())
|
|
}
|
|
|
|
if brain.GetThinkTick() != BlankBrainTick {
|
|
t.Errorf("Expected think tick %d, got %d", BlankBrainTick, brain.GetThinkTick())
|
|
}
|
|
}
|
|
|
|
func TestBlankBrainThink(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
brain := NewBlankBrain(npc, logger)
|
|
|
|
// Blank brain Think should do nothing and not error
|
|
err := brain.Think()
|
|
if err != nil {
|
|
t.Errorf("Expected no error from blank brain Think, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewLuaBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
npc.spawnScript = "test_script.lua"
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
|
|
brain := NewLuaBrain(npc, logger, luaInterface)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewLuaBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeLua {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeLua, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestLuaBrainThink(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
npc.spawnScript = "test_script.lua"
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
|
|
brain := NewLuaBrain(npc, logger, luaInterface)
|
|
|
|
err := brain.Think()
|
|
if err != nil {
|
|
t.Errorf("Expected no error from Lua brain Think, got: %v", err)
|
|
}
|
|
|
|
if !luaInterface.WasExecuted() {
|
|
t.Error("Expected Lua interface to be executed")
|
|
}
|
|
|
|
if luaInterface.lastFunction != "Think" {
|
|
t.Errorf("Expected Lua function 'Think', got '%s'", luaInterface.lastFunction)
|
|
}
|
|
}
|
|
|
|
func TestLuaBrainThinkError(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
npc.spawnScript = "test_script.lua"
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
luaInterface.SetShouldError(true)
|
|
|
|
brain := NewLuaBrain(npc, logger, luaInterface)
|
|
|
|
err := brain.Think()
|
|
if err == nil {
|
|
t.Error("Expected error from Lua brain Think")
|
|
}
|
|
}
|
|
|
|
func TestNewDumbFirePetBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
target := NewMockEntity(456, "Target")
|
|
expireTime := int32(10000) // 10 seconds
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewDumbFirePetBrain(npc, target, expireTime, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("NewDumbFirePetBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeDumbFire {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDumbFire, brain.GetBrainType())
|
|
}
|
|
|
|
// Should have max hate for target
|
|
if brain.GetHate(target.GetID()) != MaxHateValue {
|
|
t.Errorf("Expected max hate for target, got %d", brain.GetHate(target.GetID()))
|
|
}
|
|
|
|
if brain.IsExpired() {
|
|
t.Error("Dumbfire pet should not be expired immediately")
|
|
}
|
|
}
|
|
|
|
func TestDumbFirePetBrainExpiry(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
target := NewMockEntity(456, "Target")
|
|
expireTime := int32(100) // 100ms
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewDumbFirePetBrain(npc, target, expireTime, logger)
|
|
|
|
// Wait for expiry
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
if !brain.IsExpired() {
|
|
t.Error("Dumbfire pet should be expired")
|
|
}
|
|
}
|
|
|
|
func TestDumbFirePetBrainExtendExpireTime(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
target := NewMockEntity(456, "Target")
|
|
expireTime := int32(1000)
|
|
logger := NewMockLogger()
|
|
|
|
brain := NewDumbFirePetBrain(npc, target, expireTime, logger)
|
|
originalExpireTime := brain.GetExpireTime()
|
|
|
|
extension := int32(5000)
|
|
brain.ExtendExpireTime(extension)
|
|
|
|
newExpireTime := brain.GetExpireTime()
|
|
if newExpireTime != originalExpireTime+int64(extension) {
|
|
t.Errorf("Expected expire time %d, got %d", originalExpireTime+int64(extension), newExpireTime)
|
|
}
|
|
}
|
|
|
|
// Tests for CreateBrain factory function
|
|
|
|
func TestCreateBrainDefault(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
|
|
brain := CreateBrain(npc, BrainTypeDefault, logger)
|
|
|
|
if brain == nil {
|
|
t.Fatal("CreateBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeDefault {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDefault, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestCreateBrainCombatPet(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
logger := NewMockLogger()
|
|
|
|
brain := CreateBrain(npc, BrainTypeCombatPet, logger)
|
|
|
|
if brain.GetBrainType() != BrainTypeCombatPet {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeCombatPet, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestCreateBrainLua(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
|
|
brain := CreateBrain(npc, BrainTypeLua, logger, luaInterface)
|
|
|
|
if brain.GetBrainType() != BrainTypeLua {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeLua, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestCreateBrainDumbFire(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
target := NewMockEntity(456, "Target")
|
|
expireTime := int32(10000)
|
|
logger := NewMockLogger()
|
|
|
|
brain := CreateBrain(npc, BrainTypeDumbFire, logger, target, expireTime)
|
|
|
|
if brain.GetBrainType() != BrainTypeDumbFire {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDumbFire, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
// Tests for AIManager
|
|
|
|
func TestNewAIManager(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
if manager == nil {
|
|
t.Fatal("NewAIManager returned nil")
|
|
}
|
|
|
|
if manager.GetBrainCount() != 0 {
|
|
t.Errorf("Expected brain count 0, got %d", manager.GetBrainCount())
|
|
}
|
|
|
|
if manager.GetActiveCount() != 0 {
|
|
t.Errorf("Expected active count 0, got %d", manager.GetActiveCount())
|
|
}
|
|
|
|
if manager.GetTotalThinks() != 0 {
|
|
t.Errorf("Expected total thinks 0, got %d", manager.GetTotalThinks())
|
|
}
|
|
}
|
|
|
|
func TestAIManagerAddBrain(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
brain := NewBaseBrain(npc, logger)
|
|
npcID := npc.GetID()
|
|
|
|
err := manager.AddBrain(npcID, brain)
|
|
if err != nil {
|
|
t.Errorf("Expected no error adding brain, got: %v", err)
|
|
}
|
|
|
|
if manager.GetBrainCount() != 1 {
|
|
t.Errorf("Expected brain count 1, got %d", manager.GetBrainCount())
|
|
}
|
|
|
|
if manager.GetActiveCount() != 1 {
|
|
t.Errorf("Expected active count 1, got %d", manager.GetActiveCount())
|
|
}
|
|
|
|
retrievedBrain := manager.GetBrain(npcID)
|
|
if retrievedBrain != brain {
|
|
t.Error("Retrieved brain should be the same as added brain")
|
|
}
|
|
}
|
|
|
|
func TestAIManagerAddBrainDuplicate(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
brain1 := NewBaseBrain(npc, logger)
|
|
brain2 := NewBaseBrain(npc, logger)
|
|
npcID := npc.GetID()
|
|
|
|
err1 := manager.AddBrain(npcID, brain1)
|
|
err2 := manager.AddBrain(npcID, brain2) // Duplicate
|
|
|
|
if err1 != nil {
|
|
t.Errorf("Expected no error adding first brain, got: %v", err1)
|
|
}
|
|
|
|
if err2 == nil {
|
|
t.Error("Expected error adding duplicate brain")
|
|
}
|
|
|
|
if manager.GetBrainCount() != 1 {
|
|
t.Errorf("Expected brain count 1 after duplicate add, got %d", manager.GetBrainCount())
|
|
}
|
|
}
|
|
|
|
func TestAIManagerRemoveBrain(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
brain := NewBaseBrain(npc, logger)
|
|
npcID := npc.GetID()
|
|
|
|
manager.AddBrain(npcID, brain)
|
|
manager.RemoveBrain(npcID)
|
|
|
|
if manager.GetBrainCount() != 0 {
|
|
t.Errorf("Expected brain count 0 after removal, got %d", manager.GetBrainCount())
|
|
}
|
|
|
|
if manager.GetActiveCount() != 0 {
|
|
t.Errorf("Expected active count 0 after removal, got %d", manager.GetActiveCount())
|
|
}
|
|
|
|
retrievedBrain := manager.GetBrain(npcID)
|
|
if retrievedBrain != nil {
|
|
t.Error("Retrieved brain should be nil after removal")
|
|
}
|
|
}
|
|
|
|
func TestAIManagerCreateBrainForNPC(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
|
|
err := manager.CreateBrainForNPC(npc, BrainTypeDefault)
|
|
if err != nil {
|
|
t.Errorf("Expected no error creating brain, got: %v", err)
|
|
}
|
|
|
|
brain := manager.GetBrain(npc.GetID())
|
|
if brain == nil {
|
|
t.Error("Expected brain to be created")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeDefault {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDefault, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestAIManagerSetBrainActive(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
brain := NewBaseBrain(npc, logger)
|
|
npcID := npc.GetID()
|
|
|
|
manager.AddBrain(npcID, brain)
|
|
|
|
// Initially active
|
|
if manager.GetActiveCount() != 1 {
|
|
t.Errorf("Expected active count 1, got %d", manager.GetActiveCount())
|
|
}
|
|
|
|
// Set inactive
|
|
manager.SetBrainActive(npcID, false)
|
|
if manager.GetActiveCount() != 0 {
|
|
t.Errorf("Expected active count 0, got %d", manager.GetActiveCount())
|
|
}
|
|
|
|
// Set active again
|
|
manager.SetBrainActive(npcID, true)
|
|
if manager.GetActiveCount() != 1 {
|
|
t.Errorf("Expected active count 1, got %d", manager.GetActiveCount())
|
|
}
|
|
}
|
|
|
|
func TestAIManagerGetBrainsByType(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc1 := NewMockNPC(123, "TestNPC1")
|
|
npc2 := NewMockNPC(456, "TestNPC2")
|
|
npc3 := NewMockNPC(789, "TestNPC3")
|
|
|
|
brain1 := NewBaseBrain(npc1, logger)
|
|
brain2 := NewCombatPetBrain(npc2, logger)
|
|
brain3 := NewBlankBrain(npc3, logger)
|
|
|
|
manager.AddBrain(npc1.GetID(), brain1)
|
|
manager.AddBrain(npc2.GetID(), brain2)
|
|
manager.AddBrain(npc3.GetID(), brain3)
|
|
|
|
defaultBrains := manager.GetBrainsByType(BrainTypeDefault)
|
|
if len(defaultBrains) != 1 {
|
|
t.Errorf("Expected 1 default brain, got %d", len(defaultBrains))
|
|
}
|
|
|
|
petBrains := manager.GetBrainsByType(BrainTypeCombatPet)
|
|
if len(petBrains) != 1 {
|
|
t.Errorf("Expected 1 combat pet brain, got %d", len(petBrains))
|
|
}
|
|
|
|
blankBrains := manager.GetBrainsByType(BrainTypeBlank)
|
|
if len(blankBrains) != 1 {
|
|
t.Errorf("Expected 1 blank brain, got %d", len(blankBrains))
|
|
}
|
|
}
|
|
|
|
func TestAIManagerClearAllBrains(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc1 := NewMockNPC(123, "TestNPC1")
|
|
npc2 := NewMockNPC(456, "TestNPC2")
|
|
|
|
brain1 := NewBaseBrain(npc1, logger)
|
|
brain2 := NewBaseBrain(npc2, logger)
|
|
|
|
manager.AddBrain(npc1.GetID(), brain1)
|
|
manager.AddBrain(npc2.GetID(), brain2)
|
|
|
|
manager.ClearAllBrains()
|
|
|
|
if manager.GetBrainCount() != 0 {
|
|
t.Errorf("Expected brain count 0 after clear, got %d", manager.GetBrainCount())
|
|
}
|
|
|
|
if manager.GetActiveCount() != 0 {
|
|
t.Errorf("Expected active count 0 after clear, got %d", manager.GetActiveCount())
|
|
}
|
|
}
|
|
|
|
func TestAIManagerGetStatistics(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
npc1 := NewMockNPC(123, "TestNPC1")
|
|
npc2 := NewMockNPC(456, "TestNPC2")
|
|
|
|
brain1 := NewBaseBrain(npc1, logger)
|
|
brain2 := NewCombatPetBrain(npc2, logger)
|
|
|
|
manager.AddBrain(npc1.GetID(), brain1)
|
|
manager.AddBrain(npc2.GetID(), brain2)
|
|
|
|
stats := manager.GetStatistics()
|
|
|
|
if stats == nil {
|
|
t.Fatal("GetStatistics returned nil")
|
|
}
|
|
|
|
if stats.TotalBrains != 2 {
|
|
t.Errorf("Expected total brains 2, got %d", stats.TotalBrains)
|
|
}
|
|
|
|
if stats.ActiveBrains != 2 {
|
|
t.Errorf("Expected active brains 2, got %d", stats.ActiveBrains)
|
|
}
|
|
|
|
if len(stats.BrainsByType) == 0 {
|
|
t.Error("Expected brain types to be populated")
|
|
}
|
|
}
|
|
|
|
// Tests for utility functions
|
|
|
|
func TestGetBrainTypeName(t *testing.T) {
|
|
testCases := []struct {
|
|
brainType int8
|
|
expected string
|
|
}{
|
|
{BrainTypeDefault, "default"},
|
|
{BrainTypeCombatPet, "combat_pet"},
|
|
{BrainTypeNonCombatPet, "non_combat_pet"},
|
|
{BrainTypeBlank, "blank"},
|
|
{BrainTypeLua, "lua"},
|
|
{BrainTypeDumbFire, "dumbfire"},
|
|
{99, "unknown"}, // Unknown type
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
result := getBrainTypeName(tc.brainType)
|
|
if result != tc.expected {
|
|
t.Errorf("Expected brain type name '%s' for type %d, got '%s'", tc.expected, tc.brainType, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCurrentTimeMillis(t *testing.T) {
|
|
before := time.Now().UnixMilli()
|
|
result := currentTimeMillis()
|
|
after := time.Now().UnixMilli()
|
|
|
|
if result < before || result > after {
|
|
t.Errorf("Expected current time to be between %d and %d, got %d", before, after, result)
|
|
}
|
|
}
|
|
|
|
// Tests for AIBrainAdapter
|
|
|
|
func TestNewAIBrainAdapter(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
|
|
adapter := NewAIBrainAdapter(npc, logger)
|
|
|
|
if adapter == nil {
|
|
t.Fatal("NewAIBrainAdapter returned nil")
|
|
}
|
|
|
|
if adapter.GetNPC() != npc {
|
|
t.Error("Expected adapter NPC to be the provided NPC")
|
|
}
|
|
}
|
|
|
|
func TestAIBrainAdapterSetupDefaultBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
adapter := NewAIBrainAdapter(npc, logger)
|
|
|
|
brain := adapter.SetupDefaultBrain()
|
|
|
|
if brain == nil {
|
|
t.Fatal("SetupDefaultBrain returned nil")
|
|
}
|
|
|
|
if brain.GetBrainType() != BrainTypeDefault {
|
|
t.Errorf("Expected brain type %d, got %d", BrainTypeDefault, brain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestAIBrainAdapterSetupPetBrain(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestPet")
|
|
logger := NewMockLogger()
|
|
adapter := NewAIBrainAdapter(npc, logger)
|
|
|
|
// Test combat pet brain
|
|
combatBrain := adapter.SetupPetBrain(true)
|
|
if combatBrain.GetBrainType() != BrainTypeCombatPet {
|
|
t.Errorf("Expected combat pet brain type %d, got %d", BrainTypeCombatPet, combatBrain.GetBrainType())
|
|
}
|
|
|
|
// Test non-combat pet brain
|
|
nonCombatBrain := adapter.SetupPetBrain(false)
|
|
if nonCombatBrain.GetBrainType() != BrainTypeNonCombatPet {
|
|
t.Errorf("Expected non-combat pet brain type %d, got %d", BrainTypeNonCombatPet, nonCombatBrain.GetBrainType())
|
|
}
|
|
}
|
|
|
|
func TestAIBrainAdapterProcessAI(t *testing.T) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
adapter := NewAIBrainAdapter(npc, logger)
|
|
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
err := adapter.ProcessAI(brain)
|
|
if err != nil {
|
|
t.Errorf("Expected no error processing AI, got: %v", err)
|
|
}
|
|
|
|
// Test with nil brain
|
|
err = adapter.ProcessAI(nil)
|
|
if err == nil {
|
|
t.Error("Expected error processing AI with nil brain")
|
|
}
|
|
|
|
// Test with inactive brain
|
|
brain.SetActive(false)
|
|
err = adapter.ProcessAI(brain)
|
|
if err != nil {
|
|
t.Errorf("Expected no error processing inactive AI, got: %v", err)
|
|
}
|
|
}
|
|
|
|
// Tests for HateListDebugger
|
|
|
|
func TestNewHateListDebugger(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
debugger := NewHateListDebugger(logger)
|
|
|
|
if debugger == nil {
|
|
t.Fatal("NewHateListDebugger returned nil")
|
|
}
|
|
}
|
|
|
|
func TestHateListDebuggerPrintHateList(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
debugger := NewHateListDebugger(logger)
|
|
|
|
hateList := make(map[int32]*HateEntry)
|
|
hateList[123] = &HateEntry{EntityID: 123, HateValue: 500}
|
|
hateList[456] = &HateEntry{EntityID: 456, HateValue: 300}
|
|
|
|
debugger.PrintHateList("TestNPC", hateList)
|
|
|
|
messages := logger.GetMessages()
|
|
if len(messages) == 0 {
|
|
t.Error("Expected debug messages to be logged")
|
|
}
|
|
}
|
|
|
|
func TestHateListDebuggerPrintEncounterList(t *testing.T) {
|
|
logger := NewMockLogger()
|
|
debugger := NewHateListDebugger(logger)
|
|
|
|
encounterList := make(map[int32]*EncounterEntry)
|
|
encounterList[123] = &EncounterEntry{EntityID: 123, IsPlayer: true}
|
|
encounterList[456] = &EncounterEntry{EntityID: 456, IsBot: true}
|
|
|
|
debugger.PrintEncounterList("TestNPC", encounterList)
|
|
|
|
messages := logger.GetMessages()
|
|
if len(messages) == 0 {
|
|
t.Error("Expected debug messages to be logged")
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
|
|
func BenchmarkHateListAddHate(b *testing.B) {
|
|
hateList := NewHateList()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
hateList.AddHate(int32(i), 100)
|
|
}
|
|
}
|
|
|
|
func BenchmarkHateListGetMostHated(b *testing.B) {
|
|
hateList := NewHateList()
|
|
|
|
// Populate with some data
|
|
for i := 0; i < 100; i++ {
|
|
hateList.AddHate(int32(i), int32(i*10))
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
hateList.GetMostHated()
|
|
}
|
|
}
|
|
|
|
func BenchmarkBrainThink(b *testing.B) {
|
|
npc := NewMockNPC(123, "TestNPC")
|
|
logger := NewMockLogger()
|
|
brain := NewBaseBrain(npc, logger)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
brain.Think()
|
|
}
|
|
}
|
|
|
|
func BenchmarkEncounterListAddEntity(b *testing.B) {
|
|
encounterList := NewEncounterList()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
encounterList.AddEntity(int32(i), int32(i*10), i%2 == 0, i%3 == 0)
|
|
}
|
|
}
|
|
|
|
func BenchmarkAIManagerProcessAllBrains(b *testing.B) {
|
|
logger := NewMockLogger()
|
|
luaInterface := NewMockLuaInterface()
|
|
manager := NewAIManager(logger, luaInterface)
|
|
|
|
// Add some brains
|
|
for i := 0; i < 10; i++ {
|
|
npc := NewMockNPC(int32(i), "TestNPC")
|
|
brain := NewBaseBrain(npc, logger)
|
|
manager.AddBrain(int32(i), brain)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
manager.ProcessAllBrains()
|
|
}
|
|
} |