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