package tradeskills import ( "testing" "time" ) func TestTradeskillEvent(t *testing.T) { event := &TradeskillEvent{ Name: "Test Event", Icon: 1234, Technique: TechniqueSkillAlchemy, SuccessProgress: 25, SuccessDurability: 0, SuccessHP: 0, SuccessPower: -10, SuccessSpellID: 0, SuccessItemID: 0, FailProgress: -10, FailDurability: -25, FailHP: 0, FailPower: 0, } // Test Copy method copied := event.Copy() if copied == nil { t.Fatal("Copy returned nil") } if copied.Name != event.Name { t.Errorf("Expected name %s, got %s", event.Name, copied.Name) } if copied.Technique != event.Technique { t.Errorf("Expected technique %d, got %d", event.Technique, copied.Technique) } // Test Copy with nil var nilEvent *TradeskillEvent copiedNil := nilEvent.Copy() if copiedNil != nil { t.Error("Copy of nil should return nil") } } func TestTradeskillManager(t *testing.T) { manager := NewTradeskillManager() if manager == nil { t.Fatal("NewTradeskillManager returned nil") } // Test initial state if manager.IsClientCrafting(12345) { t.Error("New manager should not have any active crafting sessions") } // Test begin crafting request := CraftingRequest{ PlayerID: 12345, RecipeID: 67890, TableSpawnID: 11111, Components: []ComponentUsage{ {ItemUniqueID: 22222, Quantity: 2}, {ItemUniqueID: 33333, Quantity: 1}, }, Quantity: 1, } err := manager.BeginCrafting(request) if err != nil { t.Fatalf("BeginCrafting failed: %v", err) } // Test client is now crafting if !manager.IsClientCrafting(12345) { t.Error("Client should be crafting after BeginCrafting") } // Test get tradeskill tradeskill := manager.GetTradeskill(12345) if tradeskill == nil { t.Fatal("GetTradeskill returned nil") } if tradeskill.PlayerID != 12345 { t.Errorf("Expected player ID 12345, got %d", tradeskill.PlayerID) } if tradeskill.RecipeID != 67890 { t.Errorf("Expected recipe ID 67890, got %d", tradeskill.RecipeID) } // Test stop crafting err = manager.StopCrafting(12345) if err != nil { t.Fatalf("StopCrafting failed: %v", err) } // Test client is no longer crafting if manager.IsClientCrafting(12345) { t.Error("Client should not be crafting after StopCrafting") } } func TestTradeskillSession(t *testing.T) { now := time.Now() tradeskill := &Tradeskill{ PlayerID: 12345, TableSpawnID: 11111, RecipeID: 67890, CurrentProgress: 500, CurrentDurability: 800, NextUpdateTime: now.Add(time.Second), UsedComponents: []ComponentUsage{ {ItemUniqueID: 22222, Quantity: 2}, }, StartTime: now, LastUpdate: now, } // Test completion check if tradeskill.IsComplete() { t.Error("Tradeskill with 500 progress should not be complete") } tradeskill.CurrentProgress = MaxProgress if !tradeskill.IsComplete() { t.Error("Tradeskill with max progress should be complete") } // Test failure check if tradeskill.IsFailed() { t.Error("Tradeskill with 800 durability should not be failed") } tradeskill.CurrentDurability = MinDurability if !tradeskill.IsFailed() { t.Error("Tradeskill with min durability should be failed") } // Test update check tradeskill.NextUpdateTime = now.Add(-time.Second) // Past time if !tradeskill.NeedsUpdate() { t.Error("Tradeskill with past update time should need update") } // Test reset tradeskill.Reset() if tradeskill.CurrentProgress != MinProgress { t.Errorf("Expected progress %d after reset, got %d", MinProgress, tradeskill.CurrentProgress) } if tradeskill.CurrentDurability != MaxDurability { t.Errorf("Expected durability %d after reset, got %d", MaxDurability, tradeskill.CurrentDurability) } } func TestMasterTradeskillEventsList(t *testing.T) { eventsList := NewMasterTradeskillEventsList() if eventsList == nil { t.Fatal("NewMasterTradeskillEventsList returned nil") } // Test initial state if eventsList.Size() != 0 { t.Error("New events list should be empty") } // Test add event event := &TradeskillEvent{ Name: "Test Event", Icon: 1234, Technique: TechniqueSkillAlchemy, } eventsList.AddEvent(event) if eventsList.Size() != 1 { t.Errorf("Expected size 1 after adding event, got %d", eventsList.Size()) } // Test get by technique events := eventsList.GetEventByTechnique(TechniqueSkillAlchemy) if len(events) != 1 { t.Errorf("Expected 1 event for alchemy, got %d", len(events)) } if events[0].Name != "Test Event" { t.Errorf("Expected event name 'Test Event', got %s", events[0].Name) } // Test get by non-existent technique noEvents := eventsList.GetEventByTechnique(TechniqueSkillFletching) if len(noEvents) != 0 { t.Errorf("Expected 0 events for fletching, got %d", len(noEvents)) } // Test add nil event eventsList.AddEvent(nil) if eventsList.Size() != 1 { t.Error("Adding nil event should not change size") } // Test clear eventsList.Clear() if eventsList.Size() != 0 { t.Error("Events list should be empty after Clear") } } func TestValidTechnique(t *testing.T) { validTechniques := []uint32{ TechniqueSkillAlchemy, TechniqueSkillTailoring, TechniqueSkillFletching, TechniqueSkillJewelcrafting, TechniqueSkillProvisioning, TechniqueSkillScribing, TechniqueSkillTransmuting, TechniqueSkillArtistry, TechniqueSkillCarpentry, TechniqueSkillMetalworking, TechniqueSkillMetalshaping, TechniqueSkillStoneworking, } for _, technique := range validTechniques { if !IsValidTechnique(technique) { t.Errorf("Technique %d should be valid", technique) } } // Test invalid technique if IsValidTechnique(999999) { t.Error("Invalid technique should not be valid") } } func TestDatabaseOperations(t *testing.T) { t.Skip("Database operations require actual database connection - skipping for basic validation") // This test would work with a real database connection // For now, just test that the interface methods exist and compile // Mock database service var dbService DatabaseService _ = dbService // Ensure interface compiles } func TestAnimationMethods(t *testing.T) { manager := NewTradeskillManager() testCases := []struct { technique uint32 version int16 expectNonZero bool }{ {TechniqueSkillAlchemy, 500, true}, {TechniqueSkillAlchemy, 1000, true}, {TechniqueSkillTailoring, 500, true}, {TechniqueSkillFletching, 1000, true}, {TechniqueSkillScribing, 500, false}, // No animations for scribing {999999, 500, false}, // Invalid technique } for _, tc := range testCases { successAnim := manager.GetTechniqueSuccessAnim(tc.version, tc.technique) failureAnim := manager.GetTechniqueFailureAnim(tc.version, tc.technique) idleAnim := manager.GetTechniqueIdleAnim(tc.version, tc.technique) if tc.expectNonZero { if successAnim == 0 { t.Errorf("Expected non-zero success animation for technique %d, version %d", tc.technique, tc.version) } if failureAnim == 0 { t.Errorf("Expected non-zero failure animation for technique %d, version %d", tc.technique, tc.version) } if idleAnim == 0 { t.Errorf("Expected non-zero idle animation for technique %d, version %d", tc.technique, tc.version) } } } // Test miss target animations missAnim := manager.GetMissTargetAnim(500) if missAnim == 0 { t.Error("Expected non-zero miss target animation for version 500") } killMissAnim := manager.GetKillMissTargetAnim(1000) if killMissAnim == 0 { t.Error("Expected non-zero kill miss target animation for version 1000") } } func TestConfigurationUpdate(t *testing.T) { manager := NewTradeskillManager() // Test valid configuration err := manager.UpdateConfiguration(1.0, 2.0, 10.0, 87.0, 30.0) if err != nil { t.Errorf("Valid configuration update failed: %v", err) } // Test invalid configuration (doesn't add to 100%) err = manager.UpdateConfiguration(1.0, 2.0, 10.0, 80.0, 30.0) // Only adds to 93% if err != nil { t.Errorf("Invalid configuration should not return error, should use defaults: %v", err) } } func TestPacketHelper(t *testing.T) { helper := &PacketHelper{} // Test progress stage calculation testCases := []struct { progress int32 expected int8 }{ {0, 0}, {300, 0}, {400, 1}, {550, 1}, {600, 2}, {750, 2}, {800, 3}, {950, 3}, {1000, 4}, {1100, 4}, // Clamped to max } for _, tc := range testCases { result := helper.CalculateProgressStage(tc.progress) if result != tc.expected { t.Errorf("Progress %d: expected stage %d, got %d", tc.progress, tc.expected, result) } } // Test mass production quantities quantities := helper.GetMassProductionQuantities(3) if len(quantities) == 0 { t.Error("Should return at least base quantity") } if quantities[0] != 1 { t.Error("First quantity should always be 1") } // Test component validation components := []ComponentUsage{ {ItemUniqueID: 12345, Quantity: 2}, {ItemUniqueID: 67890, Quantity: 1}, } err := helper.ValidateRecipeComponents(12345, components) if err != nil { t.Errorf("Valid components should pass validation: %v", err) } // Test invalid components invalidComponents := []ComponentUsage{ {ItemUniqueID: 0, Quantity: 2}, // Invalid unique ID } err = helper.ValidateRecipeComponents(12345, invalidComponents) if err == nil { t.Error("Invalid components should fail validation") } // Test packet type calculation packetType := helper.CalculateItemPacketType(500) if packetType == 0 { t.Error("Should return non-zero packet type") } // Test value clamping clampedProgress := helper.ClampProgress(-100) if clampedProgress != MinProgress { t.Errorf("Expected clamped progress %d, got %d", MinProgress, clampedProgress) } clampedDurability := helper.ClampDurability(2000) if clampedDurability != MaxDurability { t.Errorf("Expected clamped durability %d, got %d", MaxDurability, clampedDurability) } } func BenchmarkTradeskillManagerProcess(b *testing.B) { manager := NewTradeskillManager() // Add some test sessions for i := 0; i < 10; i++ { request := CraftingRequest{ PlayerID: uint32(i + 1), RecipeID: 67890, TableSpawnID: 11111, Components: []ComponentUsage{ {ItemUniqueID: 22222, Quantity: 2}, }, Quantity: 1, } manager.BeginCrafting(request) } b.ResetTimer() for i := 0; i < b.N; i++ { manager.Process() } } func BenchmarkEventListAccess(b *testing.B) { eventsList := NewMasterTradeskillEventsList() // Add test events for i := 0; i < 100; i++ { event := &TradeskillEvent{ Name: "Test Event", Icon: int16(i), Technique: TechniqueSkillAlchemy, } eventsList.AddEvent(event) } b.ResetTimer() for i := 0; i < b.N; i++ { eventsList.GetEventByTechnique(TechniqueSkillAlchemy) } }