1257 lines
34 KiB
Go
1257 lines
34 KiB
Go
package transmute
|
|
|
|
import (
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
// Mock implementations for testing
|
|
|
|
// MockItem implements the Item interface for testing
|
|
type MockItem struct {
|
|
id int32
|
|
uniqueID int32
|
|
name string
|
|
adventureDefaultLevel int32
|
|
itemFlags int32
|
|
itemFlags2 int32
|
|
tier int32
|
|
stackCount int32
|
|
count int32
|
|
}
|
|
|
|
func NewMockItem(id, uniqueID int32, name string, level int32) *MockItem {
|
|
return &MockItem{
|
|
id: id,
|
|
uniqueID: uniqueID,
|
|
name: name,
|
|
adventureDefaultLevel: level,
|
|
tier: ItemTagLegendary,
|
|
stackCount: 1,
|
|
count: 1,
|
|
}
|
|
}
|
|
|
|
func (m *MockItem) GetID() int32 { return m.id }
|
|
func (m *MockItem) GetUniqueID() int32 { return m.uniqueID }
|
|
func (m *MockItem) GetName() string { return m.name }
|
|
func (m *MockItem) GetAdventureDefaultLevel() int32 { return m.adventureDefaultLevel }
|
|
func (m *MockItem) GetItemFlags() int32 { return m.itemFlags }
|
|
func (m *MockItem) GetItemFlags2() int32 { return m.itemFlags2 }
|
|
func (m *MockItem) GetTier() int32 { return m.tier }
|
|
func (m *MockItem) GetStackCount() int32 { return m.stackCount }
|
|
func (m *MockItem) SetCount(count int32) { m.count = count }
|
|
func (m *MockItem) CreateItemLink(version int32, detailed bool) string {
|
|
return "[" + m.name + "]"
|
|
}
|
|
|
|
// MockPlayer implements the Player interface for testing
|
|
type MockPlayer struct {
|
|
items map[int32]Item
|
|
skills map[string]Skill
|
|
stats map[int32]int32
|
|
name string
|
|
zone Zone
|
|
}
|
|
|
|
func NewMockPlayer(name string) *MockPlayer {
|
|
return &MockPlayer{
|
|
items: make(map[int32]Item),
|
|
skills: make(map[string]Skill),
|
|
stats: make(map[int32]int32),
|
|
name: name,
|
|
}
|
|
}
|
|
|
|
func (m *MockPlayer) GetItemList() map[int32]Item { return m.items }
|
|
func (m *MockPlayer) GetItemFromUniqueID(uniqueID int32) Item { return m.items[uniqueID] }
|
|
func (m *MockPlayer) GetSkillByName(skillName string) Skill { return m.skills[skillName] }
|
|
func (m *MockPlayer) GetStat(statType int32) int32 { return m.stats[statType] }
|
|
func (m *MockPlayer) GetName() string { return m.name }
|
|
func (m *MockPlayer) GetZone() Zone { return m.zone }
|
|
func (m *MockPlayer) RemoveItem(item Item, deleteItem bool) bool { delete(m.items, item.GetUniqueID()); return true }
|
|
func (m *MockPlayer) AddItem(item Item) (bool, error) { m.items[item.GetUniqueID()] = item; return true, nil }
|
|
func (m *MockPlayer) IncreaseSkill(skillName string, amount int32) error { return nil }
|
|
|
|
// MockClient implements the Client interface for testing
|
|
type MockClient struct {
|
|
version int32
|
|
transmuteID int32
|
|
packets [][]byte
|
|
messages []string
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
func NewMockClient(version int32) *MockClient {
|
|
return &MockClient{
|
|
version: version,
|
|
packets: make([][]byte, 0),
|
|
messages: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
func (m *MockClient) GetVersion() int32 { return m.version }
|
|
func (m *MockClient) GetTransmuteID() int32 { return m.transmuteID }
|
|
func (m *MockClient) SetTransmuteID(id int32) { m.transmuteID = id }
|
|
func (m *MockClient) QueuePacket(packet []byte) {
|
|
m.mutex.Lock()
|
|
m.packets = append(m.packets, packet)
|
|
m.mutex.Unlock()
|
|
}
|
|
func (m *MockClient) SimpleMessage(channel int32, message string) {
|
|
m.mutex.Lock()
|
|
m.messages = append(m.messages, message)
|
|
m.mutex.Unlock()
|
|
}
|
|
func (m *MockClient) Message(channel int32, format string, args ...any) {
|
|
// Simple implementation for testing
|
|
m.SimpleMessage(channel, format)
|
|
}
|
|
func (m *MockClient) AddItem(item Item, itemDeleted *bool) error {
|
|
*itemDeleted = false
|
|
return nil
|
|
}
|
|
|
|
func (m *MockClient) GetPackets() [][]byte {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
return append([][]byte(nil), m.packets...)
|
|
}
|
|
|
|
func (m *MockClient) GetMessages() []string {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
return append([]string(nil), m.messages...)
|
|
}
|
|
|
|
// MockSkill implements the Skill interface for testing
|
|
type MockSkill struct {
|
|
current int32
|
|
max int32
|
|
}
|
|
|
|
func NewMockSkill(current, max int32) *MockSkill {
|
|
return &MockSkill{current: current, max: max}
|
|
}
|
|
|
|
func (m *MockSkill) GetCurrentValue() int32 { return m.current }
|
|
func (m *MockSkill) GetMaxValue() int32 { return m.max }
|
|
|
|
// MockZone implements the Zone interface for testing
|
|
type MockZone struct{}
|
|
|
|
func (m *MockZone) ProcessSpell(spell Spell, caster Player) error {
|
|
// For testing, we'll simulate spell processing
|
|
return nil
|
|
}
|
|
|
|
// MockSpell implements the Spell interface for testing
|
|
type MockSpell struct {
|
|
id int32
|
|
name string
|
|
}
|
|
|
|
func (m *MockSpell) GetID() int32 { return m.id }
|
|
func (m *MockSpell) GetName() string { return m.name }
|
|
|
|
// MockSpellMaster implements the SpellMaster interface for testing
|
|
type MockSpellMaster struct {
|
|
spells map[int32]Spell
|
|
}
|
|
|
|
func NewMockSpellMaster() *MockSpellMaster {
|
|
return &MockSpellMaster{
|
|
spells: make(map[int32]Spell),
|
|
}
|
|
}
|
|
|
|
func (m *MockSpellMaster) GetSpell(spellID int32, tier int32) Spell {
|
|
return m.spells[spellID]
|
|
}
|
|
|
|
// MockItemMaster implements the ItemMaster interface for testing
|
|
type MockItemMaster struct {
|
|
items map[int32]Item
|
|
}
|
|
|
|
func NewMockItemMaster() *MockItemMaster {
|
|
return &MockItemMaster{
|
|
items: make(map[int32]Item),
|
|
}
|
|
}
|
|
|
|
func (m *MockItemMaster) GetItem(itemID int32) Item {
|
|
return m.items[itemID]
|
|
}
|
|
|
|
func (m *MockItemMaster) CreateItem(itemID int32) Item {
|
|
if item, exists := m.items[itemID]; exists {
|
|
// Return a copy
|
|
mockItem := item.(*MockItem)
|
|
return &MockItem{
|
|
id: mockItem.id,
|
|
uniqueID: mockItem.uniqueID,
|
|
name: mockItem.name,
|
|
adventureDefaultLevel: mockItem.adventureDefaultLevel,
|
|
itemFlags: mockItem.itemFlags,
|
|
itemFlags2: mockItem.itemFlags2,
|
|
tier: mockItem.tier,
|
|
stackCount: mockItem.stackCount,
|
|
count: 1,
|
|
}
|
|
}
|
|
// Create a default item if not found
|
|
return NewMockItem(itemID, itemID, "Mock Item", 50)
|
|
}
|
|
|
|
// Test database functionality
|
|
func TestDatabaseOperations(t *testing.T) {
|
|
// Create temporary database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_transmute.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Test LoadTransmutingTiers (should populate default tiers)
|
|
tiers, err := db.LoadTransmutingTiers()
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
if len(tiers) == 0 {
|
|
t.Fatal("Expected default tiers to be loaded")
|
|
}
|
|
|
|
expectedTiers := 10 // Should have 10 default tiers (1-9, 10-19, ..., 90-100)
|
|
if len(tiers) != expectedTiers {
|
|
t.Errorf("Expected %d default tiers, got %d", expectedTiers, len(tiers))
|
|
}
|
|
|
|
// Verify first tier
|
|
firstTier := tiers[0]
|
|
if firstTier.MinLevel != 1 || firstTier.MaxLevel != 9 {
|
|
t.Errorf("Expected first tier to be 1-9, got %d-%d", firstTier.MinLevel, firstTier.MaxLevel)
|
|
}
|
|
|
|
// Test GetTransmutingTierByLevel
|
|
tier, err := db.GetTransmutingTierByLevel(5)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get tier by level: %v", err)
|
|
}
|
|
|
|
if tier.MinLevel != 1 || tier.MaxLevel != 9 {
|
|
t.Errorf("Expected tier 1-9 for level 5, got %d-%d", tier.MinLevel, tier.MaxLevel)
|
|
}
|
|
|
|
// Test non-existent level
|
|
_, err = db.GetTransmutingTierByLevel(200)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent tier level")
|
|
}
|
|
|
|
// Test SaveTransmutingTier
|
|
newTier := &TransmutingTier{
|
|
MinLevel: 101,
|
|
MaxLevel: 110,
|
|
FragmentID: 2001,
|
|
PowderID: 2002,
|
|
InfusionID: 2003,
|
|
ManaID: 2004,
|
|
}
|
|
|
|
err = db.SaveTransmutingTier(newTier)
|
|
if err != nil {
|
|
t.Fatalf("Failed to save new tier: %v", err)
|
|
}
|
|
|
|
// Verify it was saved
|
|
savedTier, err := db.GetTransmutingTierByLevel(105)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get saved tier: %v", err)
|
|
}
|
|
|
|
if savedTier.FragmentID != 2001 {
|
|
t.Errorf("Expected fragment ID 2001, got %d", savedTier.FragmentID)
|
|
}
|
|
|
|
// Test TransmutingTierExists
|
|
exists, err := db.TransmutingTierExists(101, 110)
|
|
if err != nil {
|
|
t.Fatalf("Failed to check tier existence: %v", err)
|
|
}
|
|
|
|
if !exists {
|
|
t.Error("Expected tier 101-110 to exist")
|
|
}
|
|
|
|
exists, err = db.TransmutingTierExists(999, 1000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to check non-existent tier: %v", err)
|
|
}
|
|
|
|
if exists {
|
|
t.Error("Expected tier 999-1000 not to exist")
|
|
}
|
|
|
|
// Test UpdateTransmutingTier
|
|
updatedTier := &TransmutingTier{
|
|
MinLevel: 101,
|
|
MaxLevel: 110,
|
|
FragmentID: 3001,
|
|
PowderID: 3002,
|
|
InfusionID: 3003,
|
|
ManaID: 3004,
|
|
}
|
|
|
|
err = db.UpdateTransmutingTier(101, 110, updatedTier)
|
|
if err != nil {
|
|
t.Fatalf("Failed to update tier: %v", err)
|
|
}
|
|
|
|
// Verify update
|
|
updated, err := db.GetTransmutingTierByLevel(105)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get updated tier: %v", err)
|
|
}
|
|
|
|
if updated.FragmentID != 3001 {
|
|
t.Errorf("Expected updated fragment ID 3001, got %d", updated.FragmentID)
|
|
}
|
|
|
|
// Test DeleteTransmutingTier
|
|
err = db.DeleteTransmutingTier(101, 110)
|
|
if err != nil {
|
|
t.Fatalf("Failed to delete tier: %v", err)
|
|
}
|
|
|
|
// Verify deletion
|
|
_, err = db.GetTransmutingTierByLevel(105)
|
|
if err == nil {
|
|
t.Error("Expected error after deleting tier")
|
|
}
|
|
}
|
|
|
|
func TestDatabaseValidation(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_validation.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Test saving nil tier
|
|
err = db.SaveTransmutingTier(nil)
|
|
if err == nil {
|
|
t.Error("Expected error when saving nil tier")
|
|
}
|
|
|
|
// Test invalid level range
|
|
invalidTier := &TransmutingTier{
|
|
MinLevel: -1,
|
|
MaxLevel: 10,
|
|
}
|
|
|
|
err = db.SaveTransmutingTier(invalidTier)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid level range")
|
|
}
|
|
|
|
// Test min > max
|
|
invalidTier.MinLevel = 20
|
|
invalidTier.MaxLevel = 10
|
|
|
|
err = db.SaveTransmutingTier(invalidTier)
|
|
if err == nil {
|
|
t.Error("Expected error when min level > max level")
|
|
}
|
|
|
|
// Test invalid material IDs
|
|
invalidTier.MinLevel = 10
|
|
invalidTier.MaxLevel = 20
|
|
invalidTier.FragmentID = 0
|
|
|
|
err = db.SaveTransmutingTier(invalidTier)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid material ID")
|
|
}
|
|
}
|
|
|
|
// Test transmutation logic
|
|
func TestTransmuter(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
// Add some test materials to item master
|
|
itemMaster.items[1001] = NewMockItem(1001, 1001, "Fragment", 10)
|
|
itemMaster.items[1002] = NewMockItem(1002, 1002, "Powder", 10)
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Create test database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_transmuter.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Load tiers
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
tiers := transmuter.GetTransmutingTiers()
|
|
if len(tiers) == 0 {
|
|
t.Fatal("Expected transmuting tiers to be loaded")
|
|
}
|
|
|
|
// Test item transmutability
|
|
transmutableItem := NewMockItem(500, 500, "Legendary Sword", 25)
|
|
transmutableItem.tier = ItemTagLegendary
|
|
|
|
if !transmuter.IsItemTransmutable(transmutableItem) {
|
|
t.Error("Expected legendary item to be transmutable")
|
|
}
|
|
|
|
// Test non-transmutable item (wrong tier)
|
|
nonTransmutableItem := NewMockItem(501, 501, "Common Sword", 25)
|
|
nonTransmutableItem.tier = ItemTagTreasured
|
|
|
|
if transmuter.IsItemTransmutable(nonTransmutableItem) {
|
|
t.Error("Expected treasured item not to be transmutable")
|
|
}
|
|
|
|
// Test flagged item
|
|
flaggedItem := NewMockItem(502, 502, "No-Trade Sword", 25)
|
|
flaggedItem.tier = ItemTagLegendary
|
|
flaggedItem.itemFlags = NoTransmute
|
|
|
|
if transmuter.IsItemTransmutable(flaggedItem) {
|
|
t.Error("Expected no-transmute item not to be transmutable")
|
|
}
|
|
|
|
// Test stacked item
|
|
stackedItem := NewMockItem(503, 503, "Stacked Item", 25)
|
|
stackedItem.tier = ItemTagLegendary
|
|
stackedItem.stackCount = 5
|
|
|
|
if transmuter.IsItemTransmutable(stackedItem) {
|
|
t.Error("Expected stacked item not to be transmutable")
|
|
}
|
|
}
|
|
|
|
func TestCreateItemRequest(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Set up database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_request.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
// Create test player with transmutable items
|
|
player := NewMockPlayer("TestPlayer")
|
|
transmutableItem1 := NewMockItem(600, 600, "Legendary Sword", 25)
|
|
transmutableItem1.tier = ItemTagLegendary
|
|
transmutableItem2 := NewMockItem(601, 601, "Fabled Shield", 35)
|
|
transmutableItem2.tier = ItemTagFabled
|
|
|
|
player.items[600] = transmutableItem1
|
|
player.items[601] = transmutableItem2
|
|
|
|
// Add non-transmutable item
|
|
nonTransmutableItem := NewMockItem(602, 602, "Common Helm", 25)
|
|
nonTransmutableItem.tier = ItemTagTreasured
|
|
player.items[602] = nonTransmutableItem
|
|
|
|
client := NewMockClient(1000)
|
|
|
|
// Create item request
|
|
requestID, err := transmuter.CreateItemRequest(client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create item request: %v", err)
|
|
}
|
|
|
|
if requestID == 0 {
|
|
t.Error("Expected non-zero request ID")
|
|
}
|
|
|
|
if client.GetTransmuteID() != requestID {
|
|
t.Error("Expected client transmute ID to match request ID")
|
|
}
|
|
|
|
// Verify request was stored
|
|
request := transmuter.GetActiveRequest(requestID)
|
|
if request == nil {
|
|
t.Error("Expected active request to be stored")
|
|
}
|
|
|
|
if request.Phase != PhaseItemSelection {
|
|
t.Errorf("Expected phase %d, got %d", PhaseItemSelection, request.Phase)
|
|
}
|
|
}
|
|
|
|
func TestHandleItemResponse(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Set up database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_response.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
// Create test player with transmuting skill
|
|
player := NewMockPlayer("TestPlayer")
|
|
transmutingSkill := NewMockSkill(100, 300)
|
|
player.skills["Transmuting"] = transmutingSkill
|
|
|
|
transmutableItem := NewMockItem(700, 700, "Legendary Weapon", 25)
|
|
transmutableItem.tier = ItemTagLegendary
|
|
player.items[700] = transmutableItem
|
|
|
|
client := NewMockClient(1000)
|
|
|
|
// Create initial request
|
|
requestID, err := transmuter.CreateItemRequest(client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create initial request: %v", err)
|
|
}
|
|
|
|
// Handle item response
|
|
err = transmuter.HandleItemResponse(client, player, requestID, 700)
|
|
if err != nil {
|
|
t.Fatalf("Failed to handle item response: %v", err)
|
|
}
|
|
|
|
// Verify request was updated
|
|
request := transmuter.GetActiveRequest(requestID)
|
|
if request == nil {
|
|
t.Fatal("Expected request to still exist")
|
|
}
|
|
|
|
if request.Phase != PhaseConfirmation {
|
|
t.Errorf("Expected phase %d, got %d", PhaseConfirmation, request.Phase)
|
|
}
|
|
|
|
if request.ItemID != 700 {
|
|
t.Errorf("Expected item ID 700, got %d", request.ItemID)
|
|
}
|
|
|
|
// Test insufficient skill
|
|
lowSkillPlayer := NewMockPlayer("LowSkillPlayer")
|
|
lowSkill := NewMockSkill(1, 300)
|
|
lowSkillPlayer.skills["Transmuting"] = lowSkill
|
|
|
|
highLevelItem := NewMockItem(701, 701, "High Level Item", 80)
|
|
highLevelItem.tier = ItemTagLegendary
|
|
lowSkillPlayer.items[701] = highLevelItem
|
|
|
|
requestID2, err := transmuter.CreateItemRequest(client, lowSkillPlayer)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create second request: %v", err)
|
|
}
|
|
|
|
err = transmuter.HandleItemResponse(client, lowSkillPlayer, requestID2, 701)
|
|
if err == nil {
|
|
t.Error("Expected error for insufficient transmuting skill")
|
|
}
|
|
|
|
// Test non-existent item
|
|
err = transmuter.HandleItemResponse(client, player, requestID, 9999)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent item")
|
|
}
|
|
|
|
// Test non-transmutable item
|
|
nonTransmutableItem := NewMockItem(702, 702, "Common Item", 25)
|
|
nonTransmutableItem.tier = ItemTagTreasured
|
|
player.items[702] = nonTransmutableItem
|
|
|
|
err = transmuter.HandleItemResponse(client, player, requestID, 702)
|
|
if err == nil {
|
|
t.Error("Expected error for non-transmutable item")
|
|
}
|
|
}
|
|
|
|
func TestHandleConfirmResponse(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
// Add transmute spell to spell master
|
|
transmuteSpell := &MockSpell{id: TransmuteItemSpellID, name: "Transmute Item"}
|
|
spellMaster.spells[TransmuteItemSpellID] = transmuteSpell
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Set up database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_confirm.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
// Create test setup
|
|
player := NewMockPlayer("TestPlayer")
|
|
zone := &MockZone{}
|
|
player.zone = zone
|
|
|
|
transmutableItem := NewMockItem(800, 800, "Legendary Item", 25)
|
|
transmutableItem.tier = ItemTagLegendary
|
|
player.items[800] = transmutableItem
|
|
|
|
client := NewMockClient(1000)
|
|
client.SetTransmuteID(800)
|
|
|
|
// Test successful confirmation
|
|
err = transmuter.HandleConfirmResponse(client, player, 800)
|
|
if err != nil {
|
|
t.Fatalf("Failed to handle confirm response: %v", err)
|
|
}
|
|
|
|
// Test non-existent item
|
|
err = transmuter.HandleConfirmResponse(client, player, 9999)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent item")
|
|
}
|
|
|
|
// Test player without zone
|
|
playerNoZone := NewMockPlayer("NoZonePlayer")
|
|
playerNoZone.items[800] = transmutableItem
|
|
|
|
err = transmuter.HandleConfirmResponse(client, playerNoZone, 800)
|
|
if err == nil {
|
|
t.Error("Expected error for player without zone")
|
|
}
|
|
}
|
|
|
|
// Test material calculation logic
|
|
func TestCalculateTransmuteResult(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
// Add test materials to item master
|
|
itemMaster.items[1001] = NewMockItem(1001, 1001, "Fragment", 10) // Tier 1 fragment
|
|
itemMaster.items[1002] = NewMockItem(1002, 1002, "Powder", 10) // Tier 1 powder
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Set up database and load tiers
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_materials.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
// Test legendary item (should give powder/infusion)
|
|
legendaryItem := NewMockItem(900, 900, "Legendary Item", 25)
|
|
legendaryItem.tier = ItemTagLegendary
|
|
|
|
// We can't easily test the random result, but we can test the structure
|
|
result, err := transmuter.calculateTransmuteResult(legendaryItem)
|
|
if err != nil {
|
|
t.Fatalf("Failed to calculate transmute result: %v", err)
|
|
}
|
|
|
|
if !result.Success {
|
|
t.Errorf("Expected successful result, got error: %s", result.ErrorMessage)
|
|
}
|
|
|
|
// Test item with no tier match
|
|
highLevelItem := NewMockItem(901, 901, "High Level Item", 200)
|
|
highLevelItem.tier = ItemTagLegendary
|
|
|
|
result, err = transmuter.calculateTransmuteResult(highLevelItem)
|
|
if err != nil {
|
|
t.Fatalf("Failed to calculate result for high level item: %v", err)
|
|
}
|
|
|
|
if result.Success {
|
|
t.Error("Expected failure for item with no tier match")
|
|
}
|
|
}
|
|
|
|
func TestCompleteTransmutation(t *testing.T) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
// Add test materials
|
|
fragment := NewMockItem(1001, 1001, "Fragment", 10)
|
|
powder := NewMockItem(1002, 1002, "Powder", 10)
|
|
itemMaster.items[1001] = fragment
|
|
itemMaster.items[1002] = powder
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
|
|
// Set up database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_complete.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
err = transmuter.LoadTransmutingTiers(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load transmuting tiers: %v", err)
|
|
}
|
|
|
|
// Create test setup
|
|
player := NewMockPlayer("TestPlayer")
|
|
transmutingSkill := NewMockSkill(100, 300)
|
|
player.skills["Transmuting"] = transmutingSkill
|
|
|
|
transmutableItem := NewMockItem(1000, 1000, "Test Item", 25)
|
|
transmutableItem.tier = ItemTagLegendary
|
|
player.items[1000] = transmutableItem
|
|
|
|
client := NewMockClient(1000)
|
|
client.SetTransmuteID(1000)
|
|
|
|
// Complete transmutation
|
|
err = transmuter.CompleteTransmutation(client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to complete transmutation: %v", err)
|
|
}
|
|
|
|
// Verify item was removed from player
|
|
if _, exists := player.items[1000]; exists {
|
|
t.Error("Expected transmuted item to be removed from player")
|
|
}
|
|
|
|
// Verify messages were sent
|
|
messages := client.GetMessages()
|
|
if len(messages) == 0 {
|
|
t.Error("Expected completion messages to be sent")
|
|
}
|
|
|
|
// Test non-existent item
|
|
client.SetTransmuteID(9999)
|
|
err = transmuter.CompleteTransmutation(client, player)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent item")
|
|
}
|
|
}
|
|
|
|
// Test Manager functionality
|
|
func TestManager(t *testing.T) {
|
|
// Create test database
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_manager.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
// Test initialization
|
|
err = manager.Initialize()
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize manager: %v", err)
|
|
}
|
|
|
|
tiers := manager.GetTransmutingTiers()
|
|
if len(tiers) == 0 {
|
|
t.Error("Expected tiers to be loaded after initialization")
|
|
}
|
|
|
|
// Test statistics
|
|
stats := manager.GetStatistics()
|
|
if stats["total_transmutes"] != int64(0) {
|
|
t.Error("Expected zero transmutes initially")
|
|
}
|
|
|
|
// Test validation
|
|
issues := manager.ValidateTransmutingSetup()
|
|
if len(issues) > 0 {
|
|
t.Errorf("Expected no validation issues, got: %v", issues)
|
|
}
|
|
|
|
// Test GetTierForItemLevel
|
|
tier := manager.GetTierForItemLevel(25)
|
|
if tier == nil {
|
|
t.Error("Expected to find tier for level 25")
|
|
}
|
|
|
|
if tier.MinLevel > 25 || tier.MaxLevel < 25 {
|
|
t.Errorf("Expected tier to contain level 25, got %d-%d", tier.MinLevel, tier.MaxLevel)
|
|
}
|
|
|
|
// Test GetTierForItemLevel for non-existent level
|
|
noTier := manager.GetTierForItemLevel(200)
|
|
if noTier != nil {
|
|
t.Error("Expected no tier for level 200")
|
|
}
|
|
|
|
// Test CalculateRequiredSkill
|
|
item := NewMockItem(1100, 1100, "Test Item", 25)
|
|
requiredSkill := manager.CalculateRequiredSkill(item)
|
|
expectedSkill := (25 - 5) * 5 // (level - 5) * 5 = 100
|
|
if requiredSkill != int32(expectedSkill) {
|
|
t.Errorf("Expected required skill %d, got %d", expectedSkill, requiredSkill)
|
|
}
|
|
|
|
// Test low level item
|
|
lowLevelItem := NewMockItem(1101, 1101, "Low Level Item", 3)
|
|
requiredSkill = manager.CalculateRequiredSkill(lowLevelItem)
|
|
if requiredSkill != 0 {
|
|
t.Errorf("Expected required skill 0 for low level item, got %d", requiredSkill)
|
|
}
|
|
}
|
|
|
|
func TestManagerPlayerOperations(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_player_ops.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
err = manager.Initialize()
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize manager: %v", err)
|
|
}
|
|
|
|
// Create test player
|
|
player := NewMockPlayer("TestPlayer")
|
|
transmutingSkill := NewMockSkill(100, 300)
|
|
player.skills["Transmuting"] = transmutingSkill
|
|
|
|
// Add transmutable and non-transmutable items
|
|
transmutableItem := NewMockItem(1200, 1200, "Legendary Sword", 25)
|
|
transmutableItem.tier = ItemTagLegendary
|
|
player.items[1200] = transmutableItem
|
|
|
|
nonTransmutableItem := NewMockItem(1201, 1201, "Common Sword", 25)
|
|
nonTransmutableItem.tier = ItemTagTreasured
|
|
player.items[1201] = nonTransmutableItem
|
|
|
|
// Test GetTransmutableItems
|
|
transmutableItems := manager.GetTransmutableItems(player)
|
|
if len(transmutableItems) != 1 {
|
|
t.Errorf("Expected 1 transmutable item, got %d", len(transmutableItems))
|
|
}
|
|
|
|
if transmutableItems[0].GetID() != 1200 {
|
|
t.Errorf("Expected transmutable item ID 1200, got %d", transmutableItems[0].GetID())
|
|
}
|
|
|
|
// Test CanPlayerTransmuteItem
|
|
canTransmute, reason := manager.CanPlayerTransmuteItem(player, transmutableItem)
|
|
if !canTransmute {
|
|
t.Errorf("Expected player to be able to transmute item, reason: %s", reason)
|
|
}
|
|
|
|
// Test with insufficient skill
|
|
highLevelItem := NewMockItem(1202, 1202, "High Level Item", 80)
|
|
highLevelItem.tier = ItemTagLegendary
|
|
|
|
canTransmute, reason = manager.CanPlayerTransmuteItem(player, highLevelItem)
|
|
if canTransmute {
|
|
t.Error("Expected player not to be able to transmute high level item")
|
|
}
|
|
|
|
if reason == "" {
|
|
t.Error("Expected reason for inability to transmute")
|
|
}
|
|
|
|
// Test with non-transmutable item
|
|
canTransmute, reason = manager.CanPlayerTransmuteItem(player, nonTransmutableItem)
|
|
if canTransmute {
|
|
t.Error("Expected player not to be able to transmute non-transmutable item")
|
|
}
|
|
}
|
|
|
|
func TestManagerCommandProcessing(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_commands.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
err = manager.Initialize()
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize manager: %v", err)
|
|
}
|
|
|
|
client := NewMockClient(1000)
|
|
player := NewMockPlayer("TestPlayer")
|
|
|
|
// Test stats command
|
|
result, err := manager.ProcessCommand("stats", []string{}, client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to process stats command: %v", err)
|
|
}
|
|
|
|
if result == "" {
|
|
t.Error("Expected stats command to return result")
|
|
}
|
|
|
|
// Test validate command
|
|
result, err = manager.ProcessCommand("validate", []string{}, client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to process validate command: %v", err)
|
|
}
|
|
|
|
if result == "" {
|
|
t.Error("Expected validate command to return result")
|
|
}
|
|
|
|
// Test tiers command
|
|
result, err = manager.ProcessCommand("tiers", []string{}, client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to process tiers command: %v", err)
|
|
}
|
|
|
|
if result == "" {
|
|
t.Error("Expected tiers command to return result")
|
|
}
|
|
|
|
// Test reload command
|
|
result, err = manager.ProcessCommand("reload", []string{}, client, player)
|
|
if err != nil {
|
|
t.Fatalf("Failed to process reload command: %v", err)
|
|
}
|
|
|
|
if result == "" {
|
|
t.Error("Expected reload command to return result")
|
|
}
|
|
|
|
// Test unknown command
|
|
_, err = manager.ProcessCommand("unknown", []string{}, client, player)
|
|
if err == nil {
|
|
t.Error("Expected error for unknown command")
|
|
}
|
|
}
|
|
|
|
func TestManagerStatistics(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_stats.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
// Test initial statistics
|
|
stats := manager.GetStatistics()
|
|
if stats["total_transmutes"] != int64(0) {
|
|
t.Error("Expected zero total transmutes initially")
|
|
}
|
|
|
|
// Test RecordMaterialProduced
|
|
manager.RecordMaterialProduced(1001, 5)
|
|
manager.RecordMaterialProduced(1002, 3)
|
|
manager.RecordMaterialProduced(1001, 2) // Add more of the same material
|
|
|
|
count := manager.GetMaterialProductionCount(1001)
|
|
if count != 7 {
|
|
t.Errorf("Expected material 1001 count 7, got %d", count)
|
|
}
|
|
|
|
count = manager.GetMaterialProductionCount(1002)
|
|
if count != 3 {
|
|
t.Errorf("Expected material 1002 count 3, got %d", count)
|
|
}
|
|
|
|
// Test statistics after recording
|
|
stats = manager.GetStatistics()
|
|
materialStats := stats["material_counts"].(map[int32]int64)
|
|
|
|
if materialStats[1001] != 7 {
|
|
t.Errorf("Expected material 1001 in stats to be 7, got %d", materialStats[1001])
|
|
}
|
|
|
|
// Test ResetStatistics
|
|
manager.ResetStatistics()
|
|
|
|
stats = manager.GetStatistics()
|
|
if stats["total_transmutes"] != int64(0) {
|
|
t.Error("Expected statistics to be reset")
|
|
}
|
|
|
|
count = manager.GetMaterialProductionCount(1001)
|
|
if count != 0 {
|
|
t.Error("Expected material count to be reset")
|
|
}
|
|
}
|
|
|
|
// Test concurrent operations
|
|
func TestConcurrency(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
dbPath := filepath.Join(tempDir, "test_concurrency.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to open test database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
err = manager.Initialize()
|
|
if err != nil {
|
|
t.Fatalf("Failed to initialize manager: %v", err)
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
numGoroutines := 10
|
|
numOperations := 100
|
|
|
|
// Test concurrent material recording
|
|
wg.Add(numGoroutines)
|
|
for i := 0; i < numGoroutines; i++ {
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
for j := 0; j < numOperations; j++ {
|
|
materialID := int32(1000 + (id % 5)) // Use 5 different materials
|
|
manager.RecordMaterialProduced(materialID, 1)
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// Verify concurrent operations worked correctly
|
|
stats := manager.GetStatistics()
|
|
materialStats := stats["material_counts"].(map[int32]int64)
|
|
|
|
totalRecorded := int64(0)
|
|
for _, count := range materialStats {
|
|
totalRecorded += count
|
|
}
|
|
|
|
expectedTotal := int64(numGoroutines * numOperations)
|
|
if totalRecorded != expectedTotal {
|
|
t.Errorf("Expected total recorded %d, got %d", expectedTotal, totalRecorded)
|
|
}
|
|
}
|
|
|
|
// Test packet builder
|
|
func TestPacketBuilder(t *testing.T) {
|
|
builder := NewPacketBuilder()
|
|
|
|
// Test BuildItemRequestPacket
|
|
items := []int32{100, 200, 300}
|
|
packet, err := builder.BuildItemRequestPacket(12345, items, 1000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to build item request packet: %v", err)
|
|
}
|
|
|
|
if packet == nil {
|
|
t.Error("Expected packet to be non-nil")
|
|
}
|
|
|
|
// Test empty items list
|
|
_, err = builder.BuildItemRequestPacket(12345, []int32{}, 1000)
|
|
if err == nil {
|
|
t.Error("Expected error for empty items list")
|
|
}
|
|
|
|
// Test BuildConfirmationPacket
|
|
item := NewMockItem(400, 400, "Test Item", 50)
|
|
packet, err = builder.BuildConfirmationPacket(12345, item, 1000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to build confirmation packet: %v", err)
|
|
}
|
|
|
|
if packet == nil {
|
|
t.Error("Expected packet to be non-nil")
|
|
}
|
|
|
|
// Test nil item
|
|
_, err = builder.BuildConfirmationPacket(12345, nil, 1000)
|
|
if err == nil {
|
|
t.Error("Expected error for nil item")
|
|
}
|
|
|
|
// Test BuildRewardPacket
|
|
rewardItems := []Item{
|
|
NewMockItem(500, 500, "Reward 1", 30),
|
|
NewMockItem(501, 501, "Reward 2", 30),
|
|
}
|
|
|
|
packet, err = builder.BuildRewardPacket(rewardItems, 1000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to build reward packet: %v", err)
|
|
}
|
|
|
|
if packet == nil {
|
|
t.Error("Expected packet to be non-nil")
|
|
}
|
|
|
|
// Test empty rewards
|
|
_, err = builder.BuildRewardPacket([]Item{}, 1000)
|
|
if err == nil {
|
|
t.Error("Expected error for empty rewards list")
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkIsItemTransmutable(b *testing.B) {
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
transmuter := NewTransmuter(itemMaster, spellMaster, packetBuilder)
|
|
item := NewMockItem(1000, 1000, "Test Item", 50)
|
|
item.tier = ItemTagLegendary
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
transmuter.IsItemTransmutable(item)
|
|
}
|
|
}
|
|
|
|
func BenchmarkDatabaseOperations(b *testing.B) {
|
|
tempDir := b.TempDir()
|
|
dbPath := filepath.Join(tempDir, "bench_db.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
b.Fatalf("Failed to open benchmark database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
// Load initial tiers
|
|
_, err = db.LoadTransmutingTiers()
|
|
if err != nil {
|
|
b.Fatalf("Failed to load initial tiers: %v", err)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := db.GetTransmutingTierByLevel(int32(25 + (i % 75))) // Test levels 25-99
|
|
if err != nil {
|
|
b.Fatalf("Failed to get tier by level: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkManagerOperations(b *testing.B) {
|
|
tempDir := b.TempDir()
|
|
dbPath := filepath.Join(tempDir, "bench_manager.db")
|
|
|
|
db, err := OpenDB(dbPath)
|
|
if err != nil {
|
|
b.Fatalf("Failed to open benchmark database: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
itemMaster := NewMockItemMaster()
|
|
spellMaster := NewMockSpellMaster()
|
|
packetBuilder := NewPacketBuilder()
|
|
|
|
manager := NewManager(db, itemMaster, spellMaster, packetBuilder)
|
|
defer manager.Shutdown()
|
|
|
|
err = manager.Initialize()
|
|
if err != nil {
|
|
b.Fatalf("Failed to initialize manager: %v", err)
|
|
}
|
|
|
|
item := NewMockItem(1000, 1000, "Benchmark Item", 50)
|
|
item.tier = ItemTagLegendary
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
manager.IsItemTransmutable(item)
|
|
}
|
|
} |