429 lines
11 KiB
Go
429 lines
11 KiB
Go
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)
|
|
}
|
|
}
|