eq2go/internal/object/object_test.go
2025-08-05 19:57:01 -05:00

1230 lines
31 KiB
Go

package object
import (
"strings"
"testing"
)
// Test Object creation and basic properties
func TestNewObject(t *testing.T) {
obj := NewObject()
if obj == nil {
t.Fatal("NewObject returned nil")
}
// Test default values
if obj.IsClickable() {
t.Error("New object should not be clickable by default")
}
if obj.GetDeviceID() != DeviceIDNone {
t.Errorf("Expected device ID %d, got %d", DeviceIDNone, obj.GetDeviceID())
}
if obj.GetZoneName() != "" {
t.Errorf("Expected empty zone name, got '%s'", obj.GetZoneName())
}
if !obj.IsObject() {
t.Error("Object should return true for IsObject()")
}
}
func TestObjectBasicProperties(t *testing.T) {
obj := NewObject()
// Test clickable
obj.SetClickable(true)
if !obj.IsClickable() {
t.Error("Object should be clickable after setting to true")
}
obj.SetClickable(false)
if obj.IsClickable() {
t.Error("Object should not be clickable after setting to false")
}
// Test zone name
testZone := "commonlands"
obj.SetZone(testZone)
if obj.GetZoneName() != testZone {
t.Errorf("Expected zone name '%s', got '%s'", testZone, obj.GetZoneName())
}
// Test device ID
testDeviceID := int8(5)
obj.SetDeviceID(testDeviceID)
if obj.GetDeviceID() != testDeviceID {
t.Errorf("Expected device ID %d, got %d", testDeviceID, obj.GetDeviceID())
}
}
func TestObjectMerchantProperties(t *testing.T) {
obj := NewObject()
// Test merchant ID
testMerchantID := int32(12345)
obj.SetMerchantID(testMerchantID)
if obj.GetMerchantID() != testMerchantID {
t.Errorf("Expected merchant ID %d, got %d", testMerchantID, obj.GetMerchantID())
}
// Test merchant type
testMerchantType := int8(2)
obj.SetMerchantType(testMerchantType)
if obj.GetMerchantType() != testMerchantType {
t.Errorf("Expected merchant type %d, got %d", testMerchantType, obj.GetMerchantType())
}
// Test merchant level range
testMinLevel, testMaxLevel := int8(10), int8(50)
obj.SetMerchantLevelRange(testMinLevel, testMaxLevel)
if obj.GetMerchantMinLevel() != testMinLevel {
t.Errorf("Expected min level %d, got %d", testMinLevel, obj.GetMerchantMinLevel())
}
if obj.GetMerchantMaxLevel() != testMaxLevel {
t.Errorf("Expected max level %d, got %d", testMaxLevel, obj.GetMerchantMaxLevel())
}
// Test collector flag
obj.SetCollector(true)
if !obj.IsCollector() {
t.Error("Object should be a collector after setting to true")
}
obj.SetCollector(false)
if obj.IsCollector() {
t.Error("Object should not be a collector after setting to false")
}
}
func TestObjectSize(t *testing.T) {
obj := NewObject()
// Test size
testSize := int16(150)
obj.SetSize(testSize)
if obj.GetSize() != testSize {
t.Errorf("Expected size %d, got %d", testSize, obj.GetSize())
}
// Test size offset
testOffset := int8(10)
obj.SetSizeOffset(testOffset)
if obj.GetSizeOffset() != testOffset {
t.Errorf("Expected size offset %d, got %d", testOffset, obj.GetSizeOffset())
}
}
func TestObjectCommands(t *testing.T) {
obj := NewObject()
// Test primary commands
primaryCommands := []string{"use", "examine", "talk"}
obj.SetPrimaryCommands(primaryCommands)
retrievedPrimary := obj.GetPrimaryCommands()
if len(retrievedPrimary) != len(primaryCommands) {
t.Errorf("Expected %d primary commands, got %d", len(primaryCommands), len(retrievedPrimary))
}
for i, cmd := range primaryCommands {
if retrievedPrimary[i] != cmd {
t.Errorf("Primary command %d: expected '%s', got '%s'", i, cmd, retrievedPrimary[i])
}
}
// Test secondary commands
secondaryCommands := []string{"attack", "inspect"}
obj.SetSecondaryCommands(secondaryCommands)
retrievedSecondary := obj.GetSecondaryCommands()
if len(retrievedSecondary) != len(secondaryCommands) {
t.Errorf("Expected %d secondary commands, got %d", len(secondaryCommands), len(retrievedSecondary))
}
for i, cmd := range secondaryCommands {
if retrievedSecondary[i] != cmd {
t.Errorf("Secondary command %d: expected '%s', got '%s'", i, cmd, retrievedSecondary[i])
}
}
}
func TestObjectHP(t *testing.T) {
obj := NewObject()
// Test total HP
testTotalHP := int32(1000)
obj.SetTotalHP(testTotalHP)
if obj.GetTotalHP() != testTotalHP {
t.Errorf("Expected total HP %d, got %d", testTotalHP, obj.GetTotalHP())
}
// Test current HP
testCurrentHP := int32(750)
obj.SetHP(testCurrentHP)
if obj.GetHP() != testCurrentHP {
t.Errorf("Expected current HP %d, got %d", testCurrentHP, obj.GetHP())
}
}
func TestObjectPower(t *testing.T) {
obj := NewObject()
// Test total power
testTotalPower := int32(500)
obj.SetTotalPower(testTotalPower)
if obj.GetTotalPower() != testTotalPower {
t.Errorf("Expected total power %d, got %d", testTotalPower, obj.GetTotalPower())
}
// Test current power
testCurrentPower := int32(300)
obj.SetPower(testCurrentPower)
if obj.GetPower() != testCurrentPower {
t.Errorf("Expected current power %d, got %d", testCurrentPower, obj.GetPower())
}
}
func TestObjectTransporter(t *testing.T) {
obj := NewObject()
testTransporterID := int32(9876)
obj.SetTransporterID(testTransporterID)
if obj.GetTransporterID() != testTransporterID {
t.Errorf("Expected transporter ID %d, got %d", testTransporterID, obj.GetTransporterID())
}
}
func TestObjectFlags(t *testing.T) {
obj := NewObject()
// Test sounds disabled flag
obj.SetSoundsDisabled(true)
if !obj.IsSoundsDisabled() {
t.Error("Sounds should be disabled after setting to true")
}
obj.SetSoundsDisabled(false)
if obj.IsSoundsDisabled() {
t.Error("Sounds should not be disabled after setting to false")
}
// Test omitted by DB flag
obj.SetOmittedByDBFlag(true)
if !obj.IsOmittedByDBFlag() {
t.Error("Object should be omitted by DB after setting to true")
}
obj.SetOmittedByDBFlag(false)
if obj.IsOmittedByDBFlag() {
t.Error("Object should not be omitted by DB after setting to false")
}
}
func TestObjectLoot(t *testing.T) {
obj := NewObject()
// Test loot tier
testLootTier := int8(3)
obj.SetLootTier(testLootTier)
if obj.GetLootTier() != testLootTier {
t.Errorf("Expected loot tier %d, got %d", testLootTier, obj.GetLootTier())
}
// Test loot drop type
testDropType := int8(2)
obj.SetLootDropType(testDropType)
if obj.GetLootDropType() != testDropType {
t.Errorf("Expected loot drop type %d, got %d", testDropType, obj.GetLootDropType())
}
}
func TestObjectSpawnScript(t *testing.T) {
obj := NewObject()
testScript := "test_script.lua"
obj.SetSpawnScript(testScript)
if obj.GetSpawnScript() != testScript {
t.Errorf("Expected spawn script '%s', got '%s'", testScript, obj.GetSpawnScript())
}
if !obj.GetSpawnScriptSetDB() {
t.Error("Spawn script set DB flag should be true after setting script")
}
// Test empty script
obj.SetSpawnScript("")
if obj.GetSpawnScriptSetDB() {
t.Error("Spawn script set DB flag should be false after setting empty script")
}
}
func TestObjectCommandIcon(t *testing.T) {
obj := NewObject()
// Test show command icon
obj.SetShowCommandIcon(true)
if !obj.ShowsCommandIcon() {
t.Error("Object should show command icon after setting to true")
}
obj.SetShowCommandIcon(false)
if obj.ShowsCommandIcon() {
t.Error("Object should not show command icon after setting to false")
}
}
func TestObjectCopy(t *testing.T) {
// Create original object with various properties set
original := NewObject()
original.SetClickable(true)
original.SetZone("testzone")
original.SetDeviceID(5)
original.SetMerchantID(12345)
original.SetMerchantType(2)
original.SetCollector(true)
original.SetSize(100)
original.SetSizeOffset(10)
original.SetTransporterID(9876)
original.SetTotalHP(1000)
original.SetHP(750)
original.SetShowCommandIcon(true)
// Create copy
copied := original.Copy()
if copied == nil {
t.Fatal("Copy returned nil")
}
// Verify copy has same properties
if copied.IsClickable() != original.IsClickable() {
t.Error("Copied object clickable state doesn't match original")
}
if copied.GetZoneName() != original.GetZoneName() {
t.Error("Copied object zone name doesn't match original")
}
if copied.GetDeviceID() != original.GetDeviceID() {
t.Error("Copied object device ID doesn't match original")
}
if copied.GetMerchantID() != original.GetMerchantID() {
t.Error("Copied object merchant ID doesn't match original")
}
if copied.IsCollector() != original.IsCollector() {
t.Error("Copied object collector flag doesn't match original")
}
if copied.GetTransporterID() != original.GetTransporterID() {
t.Error("Copied object transporter ID doesn't match original")
}
// Test size randomization with offset
if original.GetSizeOffset() > 0 {
// Size should be different but within reasonable range
originalSize := original.GetSize()
copiedSize := copied.GetSize()
sizeDiff := copiedSize - originalSize
offsetInt16 := int16(original.GetSizeOffset())
if sizeDiff < -offsetInt16 || sizeDiff > offsetInt16 {
t.Errorf("Copied object size randomization out of range: original=%d, copied=%d, offset=%d",
originalSize, copiedSize, original.GetSizeOffset())
}
}
// Verify they are separate objects
copied.SetClickable(false)
if copied.IsClickable() == original.IsClickable() {
t.Error("Copied object should be independent from original")
}
}
func TestObjectHandleUse(t *testing.T) {
obj := NewObject()
clientID := int32(12345)
// Test non-interactive object
err := obj.HandleUse(clientID, "use")
if err == nil {
t.Error("Expected error for non-interactive object")
}
// Test with transporter ID
obj.SetTransporterID(100)
err = obj.HandleUse(clientID, "use")
if err == nil {
t.Error("Expected error for transport system not implemented")
}
if !strings.Contains(err.Error(), "transport system not yet implemented") {
t.Errorf("Expected transport error message, got: %v", err)
}
// Test with command icon
obj.SetTransporterID(0) // Remove transporter
obj.SetShowCommandIcon(true)
obj.SetPrimaryCommands([]string{"use", "examine"})
err = obj.HandleUse(clientID, "use")
if err != nil {
t.Errorf("Expected no error for valid command, got: %v", err)
}
err = obj.HandleUse(clientID, "invalid")
if err == nil {
t.Error("Expected error for invalid command")
}
if !strings.Contains(err.Error(), "command 'invalid' not found") {
t.Errorf("Expected command not found error, got: %v", err)
}
}
func TestObjectInfo(t *testing.T) {
obj := NewObject()
obj.SetClickable(true)
obj.SetZone("testzone")
obj.SetDeviceID(5)
obj.SetMerchantID(12345)
obj.SetTransporterID(9876)
obj.SetCollector(true)
obj.SetSize(150)
obj.SetPrimaryCommands([]string{"use", "examine"})
obj.SetSecondaryCommands([]string{"attack"})
obj.SetShowCommandIcon(true)
info := obj.GetObjectInfo()
if info == nil {
t.Fatal("GetObjectInfo returned nil")
}
// Check various properties
if info["clickable"] != true {
t.Error("Info should show object as clickable")
}
if info["zone_name"] != "testzone" {
t.Error("Info should show correct zone name")
}
if info["device_id"] != int8(5) {
t.Error("Info should show correct device ID")
}
if info["merchant_id"] != int32(12345) {
t.Error("Info should show correct merchant ID")
}
if info["transporter_id"] != int32(9876) {
t.Error("Info should show correct transporter ID")
}
if info["is_collector"] != true {
t.Error("Info should show object as collector")
}
if info["primary_commands"] != 2 {
t.Error("Info should show correct primary command count")
}
if info["secondary_commands"] != 1 {
t.Error("Info should show correct secondary command count")
}
if info["shows_command_icon"] != true {
t.Error("Info should show command icon as visible")
}
}
// Test ObjectSpawn creation and integration
func TestNewObjectSpawn(t *testing.T) {
objectSpawn := NewObjectSpawn()
if objectSpawn == nil {
t.Fatal("NewObjectSpawn returned nil")
}
if objectSpawn.Spawn == nil {
t.Fatal("ObjectSpawn should have embedded Spawn")
}
// Test default spawn type
if objectSpawn.GetSpawnType() != ObjectSpawnType {
t.Errorf("Expected spawn type %d, got %d", ObjectSpawnType, objectSpawn.GetSpawnType())
}
// Test default appearance values
appearance := objectSpawn.GetAppearanceData()
if appearance.ActivityStatus != ObjectActivityStatus {
t.Errorf("Expected activity status %d, got %d", ObjectActivityStatus, appearance.ActivityStatus)
}
if appearance.Pos.State != ObjectPosState {
t.Errorf("Expected pos state %d, got %d", ObjectPosState, appearance.Pos.State)
}
if appearance.Difficulty != ObjectDifficulty {
t.Errorf("Expected difficulty %d, got %d", ObjectDifficulty, appearance.Difficulty)
}
if !objectSpawn.IsObject() {
t.Error("ObjectSpawn should return true for IsObject()")
}
}
func TestObjectSpawnMerchantProperties(t *testing.T) {
objectSpawn := NewObjectSpawn()
// Test merchant ID
testMerchantID := int32(54321)
objectSpawn.SetMerchantID(testMerchantID)
if objectSpawn.GetMerchantID() != testMerchantID {
t.Errorf("Expected merchant ID %d, got %d", testMerchantID, objectSpawn.GetMerchantID())
}
// Test merchant type
testMerchantType := int8(3)
objectSpawn.SetMerchantType(testMerchantType)
if objectSpawn.GetMerchantType() != testMerchantType {
t.Errorf("Expected merchant type %d, got %d", testMerchantType, objectSpawn.GetMerchantType())
}
// Test merchant level range
minLevel, maxLevel := int8(5), int8(25)
objectSpawn.SetMerchantLevelRange(minLevel, maxLevel)
if objectSpawn.GetMerchantMinLevel() != minLevel {
t.Errorf("Expected min level %d, got %d", minLevel, objectSpawn.GetMerchantMinLevel())
}
if objectSpawn.GetMerchantMaxLevel() != maxLevel {
t.Errorf("Expected max level %d, got %d", maxLevel, objectSpawn.GetMerchantMaxLevel())
}
// Test collector
objectSpawn.SetCollector(true)
if !objectSpawn.IsCollector() {
t.Error("ObjectSpawn should be a collector after setting to true")
}
}
func TestObjectSpawnTransporter(t *testing.T) {
objectSpawn := NewObjectSpawn()
testTransporterID := int32(11111)
objectSpawn.SetTransporterID(testTransporterID)
if objectSpawn.GetTransporterID() != testTransporterID {
t.Errorf("Expected transporter ID %d, got %d", testTransporterID, objectSpawn.GetTransporterID())
}
}
func TestObjectSpawnCommandIcon(t *testing.T) {
objectSpawn := NewObjectSpawn()
// Test setting command icon
objectSpawn.SetShowCommandIcon(true)
if !objectSpawn.ShowsCommandIcon() {
t.Error("ObjectSpawn should show command icon after setting to true")
}
objectSpawn.SetShowCommandIcon(false)
if objectSpawn.ShowsCommandIcon() {
t.Error("ObjectSpawn should not show command icon after setting to false")
}
}
func TestObjectSpawnCopy(t *testing.T) {
// Create original with properties
original := NewObjectSpawn()
original.SetClickable(true)
original.SetDeviceID(7)
original.SetMerchantID(98765)
original.SetMerchantType(4)
original.SetCollector(true)
original.SetTransporterID(55555)
original.SetDatabaseID(12345)
original.SetName("Test Object")
original.SetLevel(10)
// Create copy
copied := original.Copy()
if copied == nil {
t.Fatal("Copy returned nil")
}
// Verify properties were copied
if copied.IsClickable() != original.IsClickable() {
t.Error("Copied clickable state doesn't match")
}
if copied.GetDeviceID() != original.GetDeviceID() {
t.Error("Copied device ID doesn't match")
}
if copied.GetMerchantID() != original.GetMerchantID() {
t.Error("Copied merchant ID doesn't match")
}
if copied.IsCollector() != original.IsCollector() {
t.Error("Copied collector flag doesn't match")
}
if copied.GetTransporterID() != original.GetTransporterID() {
t.Error("Copied transporter ID doesn't match")
}
if copied.GetDatabaseID() != original.GetDatabaseID() {
t.Error("Copied database ID doesn't match")
}
if strings.TrimRight(copied.GetName(), "\x00") != strings.TrimRight(original.GetName(), "\x00") {
t.Error("Copied name doesn't match")
}
if copied.GetLevel() != original.GetLevel() {
t.Error("Copied level doesn't match")
}
// Verify independence
copied.SetClickable(false)
if copied.IsClickable() == original.IsClickable() {
t.Error("Copy should be independent from original")
}
}
func TestObjectSpawnInfo(t *testing.T) {
objectSpawn := NewObjectSpawn()
objectSpawn.SetClickable(true)
objectSpawn.SetDeviceID(8)
objectSpawn.SetMerchantID(77777)
objectSpawn.SetTransporterID(88888)
objectSpawn.SetCollector(true)
objectSpawn.SetShowCommandIcon(true)
objectSpawn.SetDatabaseID(99999)
info := objectSpawn.GetObjectInfo()
if info == nil {
t.Fatal("GetObjectInfo returned nil")
}
// Check spawn info
if info["database_id"] != int32(99999) {
t.Error("Info should show correct database ID")
}
// Check object info
if info["clickable"] != true {
t.Error("Info should show object as clickable")
}
if info["device_id"] != int8(8) {
t.Error("Info should show correct device ID")
}
if info["merchant_id"] != int32(77777) {
t.Error("Info should show correct merchant ID")
}
if info["transporter_id"] != int32(88888) {
t.Error("Info should show correct transporter ID")
}
if info["is_collector"] != true {
t.Error("Info should show object as collector")
}
if info["shows_command_icon"] != true {
t.Error("Info should show command icon as visible")
}
}
// Test ObjectManager functionality
func TestNewObjectManager(t *testing.T) {
manager := NewObjectManager()
if manager == nil {
t.Fatal("NewObjectManager returned nil")
}
if manager.GetObjectCount() != 0 {
t.Error("New manager should have 0 objects")
}
if manager.GetZoneCount() != 0 {
t.Error("New manager should have 0 zones")
}
}
func TestObjectManagerAddRemove(t *testing.T) {
manager := NewObjectManager()
// Test adding nil object
err := manager.AddObject(nil)
if err == nil {
t.Error("Expected error when adding nil object")
}
// Create test object
obj := NewObject()
obj.SetDatabaseID(12345)
obj.SetZone("testzone")
// Test adding object without database ID
objNoDB := NewObject()
err = manager.AddObject(objNoDB)
if err == nil {
t.Error("Expected error when adding object without database ID")
}
// Test adding valid object
err = manager.AddObject(obj)
if err != nil {
t.Errorf("Unexpected error adding object: %v", err)
}
if manager.GetObjectCount() != 1 {
t.Error("Manager should have 1 object after adding")
}
// Test adding duplicate
err = manager.AddObject(obj)
if err == nil {
t.Error("Expected error when adding duplicate object")
}
// Test retrieving object
retrieved := manager.GetObject(12345)
if retrieved == nil {
t.Error("Should be able to retrieve added object")
}
if retrieved.GetDatabaseID() != obj.GetDatabaseID() {
t.Error("Retrieved object should match added object")
}
// Test removing object
err = manager.RemoveObject(12345)
if err != nil {
t.Errorf("Unexpected error removing object: %v", err)
}
if manager.GetObjectCount() != 0 {
t.Error("Manager should have 0 objects after removing")
}
// Test removing non-existent object
err = manager.RemoveObject(99999)
if err == nil {
t.Error("Expected error when removing non-existent object")
}
}
func TestObjectManagerZoneOperations(t *testing.T) {
manager := NewObjectManager()
// Create objects in different zones
obj1 := NewObject()
obj1.SetDatabaseID(1)
obj1.SetZone("zone1")
obj2 := NewObject()
obj2.SetDatabaseID(2)
obj2.SetZone("zone1")
obj3 := NewObject()
obj3.SetDatabaseID(3)
obj3.SetZone("zone2")
// Add objects
manager.AddObject(obj1)
manager.AddObject(obj2)
manager.AddObject(obj3)
// Test zone count
if manager.GetZoneCount() != 2 {
t.Errorf("Expected 2 zones, got %d", manager.GetZoneCount())
}
// Test getting objects by zone
zone1Objects := manager.GetObjectsByZone("zone1")
if len(zone1Objects) != 2 {
t.Errorf("Expected 2 objects in zone1, got %d", len(zone1Objects))
}
zone2Objects := manager.GetObjectsByZone("zone2")
if len(zone2Objects) != 1 {
t.Errorf("Expected 1 object in zone2, got %d", len(zone2Objects))
}
emptyZoneObjects := manager.GetObjectsByZone("nonexistent")
if len(emptyZoneObjects) != 0 {
t.Errorf("Expected 0 objects in nonexistent zone, got %d", len(emptyZoneObjects))
}
// Test clearing zone
clearedCount := manager.ClearZone("zone1")
if clearedCount != 2 {
t.Errorf("Expected to clear 2 objects, cleared %d", clearedCount)
}
if manager.GetObjectCount() != 1 {
t.Errorf("Expected 1 object remaining, got %d", manager.GetObjectCount())
}
if manager.GetZoneCount() != 1 {
t.Errorf("Expected 1 zone remaining, got %d", manager.GetZoneCount())
}
}
func TestObjectManagerTypeFiltering(t *testing.T) {
manager := NewObjectManager()
// Create objects with different properties
interactive := NewObject()
interactive.SetDatabaseID(1)
interactive.SetZone("testzone")
interactive.SetClickable(true)
transport := NewObject()
transport.SetDatabaseID(2)
transport.SetZone("testzone")
transport.SetTransporterID(100)
merchant := NewObject()
merchant.SetDatabaseID(3)
merchant.SetZone("testzone")
merchant.SetMerchantID(200)
collector := NewObject()
collector.SetDatabaseID(4)
collector.SetZone("testzone")
collector.SetCollector(true)
// Add objects
manager.AddObject(interactive)
manager.AddObject(transport)
manager.AddObject(merchant)
manager.AddObject(collector)
// Test type filtering
interactiveObjects := manager.GetInteractiveObjects()
if len(interactiveObjects) != 1 {
t.Errorf("Expected 1 interactive object, got %d", len(interactiveObjects))
}
transportObjects := manager.GetTransportObjects()
if len(transportObjects) != 1 {
t.Errorf("Expected 1 transport object, got %d", len(transportObjects))
}
merchantObjects := manager.GetMerchantObjects()
if len(merchantObjects) != 1 {
t.Errorf("Expected 1 merchant object, got %d", len(merchantObjects))
}
collectorObjects := manager.GetCollectorObjects()
if len(collectorObjects) != 1 {
t.Errorf("Expected 1 collector object, got %d", len(collectorObjects))
}
// Test GetObjectsByType
if len(manager.GetObjectsByType("interactive")) != 1 {
t.Error("GetObjectsByType should return 1 interactive object")
}
if len(manager.GetObjectsByType("transport")) != 1 {
t.Error("GetObjectsByType should return 1 transport object")
}
if len(manager.GetObjectsByType("merchant")) != 1 {
t.Error("GetObjectsByType should return 1 merchant object")
}
if len(manager.GetObjectsByType("collector")) != 1 {
t.Error("GetObjectsByType should return 1 collector object")
}
if len(manager.GetObjectsByType("invalid")) != 0 {
t.Error("GetObjectsByType should return 0 objects for invalid type")
}
}
func TestObjectManagerUpdate(t *testing.T) {
manager := NewObjectManager()
obj := NewObject()
obj.SetDatabaseID(12345)
obj.SetZone("zone1")
obj.SetClickable(false)
manager.AddObject(obj)
// Test update
err := manager.UpdateObject(12345, func(o *Object) {
o.SetClickable(true)
o.SetZone("zone2")
})
if err != nil {
t.Errorf("Unexpected error updating object: %v", err)
}
// Verify update took effect
updated := manager.GetObject(12345)
if !updated.IsClickable() {
t.Error("Object should be clickable after update")
}
if updated.GetZoneName() != "zone2" {
t.Error("Object should be in zone2 after update")
}
// Verify zone indexing was updated
zone1Objects := manager.GetObjectsByZone("zone1")
zone2Objects := manager.GetObjectsByZone("zone2")
if len(zone1Objects) != 0 {
t.Error("zone1 should have 0 objects after update")
}
if len(zone2Objects) != 1 {
t.Error("zone2 should have 1 object after update")
}
// Test updating non-existent object
err = manager.UpdateObject(99999, func(o *Object) {})
if err == nil {
t.Error("Expected error when updating non-existent object")
}
}
func TestObjectManagerStatistics(t *testing.T) {
manager := NewObjectManager()
// Create test objects
obj1 := NewObject()
obj1.SetDatabaseID(1)
obj1.SetZone("zone1")
obj1.SetClickable(true)
obj2 := NewObject()
obj2.SetDatabaseID(2)
obj2.SetZone("zone2")
obj2.SetMerchantID(100)
manager.AddObject(obj1)
manager.AddObject(obj2)
stats := manager.GetStatistics()
if stats == nil {
t.Fatal("GetStatistics returned nil")
}
if stats["total_objects"] != 2 {
t.Error("Statistics should show 2 total objects")
}
if stats["zones_with_objects"] != 2 {
t.Error("Statistics should show 2 zones with objects")
}
if stats["interactive_objects"] != 1 {
t.Error("Statistics should show 1 interactive object")
}
if stats["merchant_objects"] != 1 {
t.Error("Statistics should show 1 merchant object")
}
zoneStats, ok := stats["objects_by_zone"].(map[string]int)
if !ok {
t.Fatal("Zone stats should be a map[string]int")
}
if zoneStats["zone1"] != 1 {
t.Error("zone1 should have 1 object in statistics")
}
if zoneStats["zone2"] != 1 {
t.Error("zone2 should have 1 object in statistics")
}
}
func TestObjectManagerShutdown(t *testing.T) {
manager := NewObjectManager()
// Add some objects
obj1 := NewObject()
obj1.SetDatabaseID(1)
obj1.SetZone("zone1")
manager.AddObject(obj1)
if manager.GetObjectCount() != 1 {
t.Error("Manager should have 1 object before shutdown")
}
// Test shutdown
manager.Shutdown()
if manager.GetObjectCount() != 0 {
t.Error("Manager should have 0 objects after shutdown")
}
if manager.GetZoneCount() != 0 {
t.Error("Manager should have 0 zones after shutdown")
}
}
// Test utility functions
func TestCreateSpecialObjectSpawns(t *testing.T) {
// Test creating merchant object spawn
merchant := CreateMerchantObjectSpawn(12345, 2)
if merchant == nil {
t.Fatal("CreateMerchantObjectSpawn returned nil")
}
if merchant.GetMerchantID() != 12345 {
t.Error("Merchant object should have correct merchant ID")
}
if merchant.GetMerchantType() != 2 {
t.Error("Merchant object should have correct merchant type")
}
if !merchant.IsClickable() {
t.Error("Merchant object should be clickable")
}
if !merchant.ShowsCommandIcon() {
t.Error("Merchant object should show command icon")
}
// Test creating transport object spawn
transport := CreateTransportObjectSpawn(54321)
if transport == nil {
t.Fatal("CreateTransportObjectSpawn returned nil")
}
if transport.GetTransporterID() != 54321 {
t.Error("Transport object should have correct transporter ID")
}
// Test creating device object spawn
device := CreateDeviceObjectSpawn(7)
if device == nil {
t.Fatal("CreateDeviceObjectSpawn returned nil")
}
if device.GetDeviceID() != 7 {
t.Error("Device object should have correct device ID")
}
// Test creating collector object spawn
collector := CreateCollectorObjectSpawn()
if collector == nil {
t.Fatal("CreateCollectorObjectSpawn returned nil")
}
if !collector.IsCollector() {
t.Error("Collector object should be a collector")
}
}
// Test ObjectSpawnManager
func TestObjectSpawnManager(t *testing.T) {
manager := NewObjectSpawnManager()
if manager == nil {
t.Fatal("NewObjectSpawnManager returned nil")
}
// Test adding object spawn
objectSpawn := NewObjectSpawn()
objectSpawn.SetDatabaseID(12345)
err := manager.AddObjectSpawn(objectSpawn)
if err != nil {
t.Errorf("Unexpected error adding object spawn: %v", err)
}
// Test retrieving object spawn
retrieved := manager.GetObjectSpawn(objectSpawn.GetID())
if retrieved == nil {
t.Error("Should be able to retrieve added object spawn")
}
// Test removing object spawn
err = manager.RemoveObjectSpawn(objectSpawn.GetID())
if err != nil {
t.Errorf("Unexpected error removing object spawn: %v", err)
}
// Test adding nil object spawn
err = manager.AddObjectSpawn(nil)
if err == nil {
t.Error("Expected error when adding nil object spawn")
}
}
// Test interface implementations
func TestObjectItem(t *testing.T) {
item := NewObjectItem(12345, "Test Item", 5)
if item == nil {
t.Fatal("NewObjectItem returned nil")
}
if item.GetID() != 12345 {
t.Error("Item should have correct ID")
}
if item.GetName() != "Test Item" {
t.Error("Item should have correct name")
}
if item.GetQuantity() != 5 {
t.Error("Item should have correct quantity")
}
// Test setting properties
item.SetQuantity(10)
if item.GetQuantity() != 10 {
t.Error("Item quantity should be updated")
}
item.SetNoTrade(true)
if !item.IsNoTrade() {
t.Error("Item should be no-trade after setting")
}
item.SetHeirloom(true)
if !item.IsHeirloom() {
t.Error("Item should be heirloom after setting")
}
item.SetAttuned(true)
if !item.IsAttuned() {
t.Error("Item should be attuned after setting")
}
// Test creation time
if item.GetCreationTime().IsZero() {
t.Error("Item should have a creation time")
}
// Test group character IDs
groupIDs := []int32{1, 2, 3}
item.SetGroupCharacterIDs(groupIDs)
retrievedIDs := item.GetGroupCharacterIDs()
if len(retrievedIDs) != len(groupIDs) {
t.Error("Group character IDs length should match")
}
for i, id := range groupIDs {
if retrievedIDs[i] != id {
t.Errorf("Group character ID %d should be %d, got %d", i, id, retrievedIDs[i])
}
}
}
func TestObjectSpawnAsEntity(t *testing.T) {
objectSpawn := NewObjectSpawn()
entity := NewObjectSpawnAsEntity(objectSpawn)
if entity == nil {
t.Fatal("NewObjectSpawnAsEntity returned nil")
}
// Test entity interface methods
if entity.GetID() != objectSpawn.GetID() {
t.Error("Entity should have same ID as object spawn")
}
if entity.IsPlayer() {
t.Error("Object entity should not be a player")
}
if entity.IsBot() {
t.Error("Object entity should not be a bot by default")
}
entity.SetBot(true)
if !entity.IsBot() {
t.Error("Object entity should be a bot after setting")
}
// Test coins
if entity.HasCoins(100) {
t.Error("Object entity should not have coins by default")
}
entity.SetCoins(500)
if !entity.HasCoins(100) {
t.Error("Object entity should have sufficient coins after setting")
}
if entity.HasCoins(1000) {
t.Error("Object entity should not have more coins than set")
}
// Test client version
if entity.GetClientVersion() != 1000 {
t.Error("Object entity should have default client version")
}
entity.SetClientVersion(2000)
if entity.GetClientVersion() != 2000 {
t.Error("Object entity should have updated client version")
}
// Test name
if entity.GetName() != "Object" {
t.Error("Object entity should have default name")
}
entity.SetName("Test Object")
if entity.GetName() != "Test Object" {
t.Error("Object entity should have updated name")
}
}
// Benchmark tests
func BenchmarkNewObject(b *testing.B) {
for i := 0; i < b.N; i++ {
NewObject()
}
}
func BenchmarkObjectCopy(b *testing.B) {
obj := NewObject()
obj.SetClickable(true)
obj.SetZone("testzone")
obj.SetMerchantID(12345)
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj.Copy()
}
}
func BenchmarkObjectManagerAdd(b *testing.B) {
manager := NewObjectManager()
objects := make([]*Object, b.N)
for i := 0; i < b.N; i++ {
obj := NewObject()
obj.SetDatabaseID(int32(i + 1))
obj.SetZone("testzone")
objects[i] = obj
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
manager.AddObject(objects[i])
}
}
func BenchmarkObjectManagerGet(b *testing.B) {
manager := NewObjectManager()
// Pre-populate with objects
for i := 0; i < 1000; i++ {
obj := NewObject()
obj.SetDatabaseID(int32(i + 1))
obj.SetZone("testzone")
manager.AddObject(obj)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
manager.GetObject(int32((i % 1000) + 1))
}
}