1394 lines
35 KiB
Go
1394 lines
35 KiB
Go
package trade
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Test coin calculation utilities
|
|
func TestCalculateCoins(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
totalCopper int64
|
|
expectedPt int32
|
|
expectedGold int32
|
|
expectedSilv int32
|
|
expectedCopp int32
|
|
}{
|
|
{"Zero coins", 0, 0, 0, 0, 0},
|
|
{"Only copper", 50, 0, 0, 0, 50},
|
|
{"Only silver", 500, 0, 0, 5, 0},
|
|
{"Only gold", 50000, 0, 5, 0, 0},
|
|
{"Only platinum", 5000000, 5, 0, 0, 0},
|
|
{"Mixed coins", 1234567, 1, 23, 45, 67},
|
|
{"Large amount", 9999999999, 9999, 99, 99, 99},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := CalculateCoins(tt.totalCopper)
|
|
if result.Platinum != tt.expectedPt {
|
|
t.Errorf("Expected platinum %d, got %d", tt.expectedPt, result.Platinum)
|
|
}
|
|
if result.Gold != tt.expectedGold {
|
|
t.Errorf("Expected gold %d, got %d", tt.expectedGold, result.Gold)
|
|
}
|
|
if result.Silver != tt.expectedSilv {
|
|
t.Errorf("Expected silver %d, got %d", tt.expectedSilv, result.Silver)
|
|
}
|
|
if result.Copper != tt.expectedCopp {
|
|
t.Errorf("Expected copper %d, got %d", tt.expectedCopp, result.Copper)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCoinsToCopper(t *testing.T) {
|
|
coins := CoinAmounts{
|
|
Platinum: 1,
|
|
Gold: 23,
|
|
Silver: 45,
|
|
Copper: 67,
|
|
}
|
|
expected := int64(1234567)
|
|
result := CoinsToCopper(coins)
|
|
if result != expected {
|
|
t.Errorf("Expected %d copper, got %d", expected, result)
|
|
}
|
|
}
|
|
|
|
func TestFormatCoins(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
copper int64
|
|
expected string
|
|
}{
|
|
{"Zero coins", 0, "0 copper"},
|
|
{"Only copper", 50, "50 copper"},
|
|
{"Only silver", 500, "5 silver"},
|
|
{"Mixed coins", 1234567, "1 platinum, 23 gold, 45 silver, 67 copper"},
|
|
{"No copper", 1230000, "1 platinum, 23 gold"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := FormatCoins(tt.copper)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected '%s', got '%s'", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Test validation utilities
|
|
func TestValidateTradeSlot(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
slot int8
|
|
maxSlots int8
|
|
expected bool
|
|
}{
|
|
{"Valid slot 0", 0, 12, true},
|
|
{"Valid slot middle", 5, 12, true},
|
|
{"Valid slot max-1", 11, 12, true},
|
|
{"Invalid negative", -1, 12, false},
|
|
{"Invalid too high", 12, 12, false},
|
|
{"Invalid way too high", 100, 12, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := ValidateTradeSlot(tt.slot, tt.maxSlots)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateTradeQuantity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
quantity int32
|
|
available int32
|
|
expected bool
|
|
}{
|
|
{"Valid quantity", 5, 10, true},
|
|
{"Valid exact match", 10, 10, true},
|
|
{"Invalid zero", 0, 10, false},
|
|
{"Invalid negative", -1, 10, false},
|
|
{"Invalid too much", 11, 10, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := ValidateTradeQuantity(tt.quantity, tt.available)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFormatTradeError(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
code int32
|
|
expected string
|
|
}{
|
|
{"Success", TradeResultSuccess, "Success"},
|
|
{"Already in trade", TradeResultAlreadyInTrade, "Item is already in the trade"},
|
|
{"No trade", TradeResultNoTrade, "Item cannot be traded"},
|
|
{"Heirloom", TradeResultHeirloom, "Heirloom item cannot be traded to this player"},
|
|
{"Invalid slot", TradeResultInvalidSlot, "Invalid or occupied trade slot"},
|
|
{"Slot out of range", TradeResultSlotOutOfRange, "Trade slot is out of range"},
|
|
{"Insufficient qty", TradeResultInsufficientQty, "Insufficient quantity to trade"},
|
|
{"Unknown error", 999, "Unknown trade error: 999"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := FormatTradeError(tt.code)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected '%s', got '%s'", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetClientMaxSlots(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
version int32
|
|
expected int8
|
|
}{
|
|
{"Very old client", 500, TradeMaxSlotsLegacy},
|
|
{"Legacy client", 561, TradeMaxSlotsLegacy},
|
|
{"Modern client", 562, TradeMaxSlotsDefault},
|
|
{"New client", 1000, TradeMaxSlotsDefault},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := GetClientMaxSlots(tt.version)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %d slots, got %d", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsValidTradeState(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
state TradeState
|
|
operation string
|
|
expected bool
|
|
}{
|
|
{"Add item active", TradeStateActive, "add_item", true},
|
|
{"Add item completed", TradeStateCompleted, "add_item", false},
|
|
{"Cancel active", TradeStateActive, "cancel", true},
|
|
{"Complete accepted", TradeStateAccepted, "complete", true},
|
|
{"Complete active", TradeStateActive, "complete", false},
|
|
{"Invalid operation", TradeStateActive, "invalid", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := IsValidTradeState(tt.state, tt.operation)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Test TradeValidationError
|
|
func TestTradeValidationError(t *testing.T) {
|
|
err := &TradeValidationError{
|
|
Code: TradeResultNoTrade,
|
|
Message: "Test error message",
|
|
}
|
|
|
|
if err.Error() != "Test error message" {
|
|
t.Errorf("Expected 'Test error message', got '%s'", err.Error())
|
|
}
|
|
}
|
|
|
|
// Test placeholder implementations
|
|
func TestPlaceholderEntity(t *testing.T) {
|
|
entity := &PlaceholderEntity{
|
|
ID: 123,
|
|
Name: "Test Entity",
|
|
IsPlayerFlag: true,
|
|
IsBotFlag: false,
|
|
CoinsAmount: 10000,
|
|
ClientVer: 800,
|
|
}
|
|
|
|
if entity.GetID() != 123 {
|
|
t.Errorf("Expected ID 123, got %d", entity.GetID())
|
|
}
|
|
|
|
if entity.GetName() != "Test Entity" {
|
|
t.Errorf("Expected name 'Test Entity', got '%s'", entity.GetName())
|
|
}
|
|
|
|
if !entity.IsPlayer() {
|
|
t.Error("Expected entity to be a player")
|
|
}
|
|
|
|
if entity.IsBot() {
|
|
t.Error("Expected entity not to be a bot")
|
|
}
|
|
|
|
if !entity.HasCoins(5000) {
|
|
t.Error("Expected entity to have enough coins")
|
|
}
|
|
|
|
if entity.HasCoins(15000) {
|
|
t.Error("Expected entity not to have enough coins")
|
|
}
|
|
|
|
if entity.GetClientVersion() != 800 {
|
|
t.Errorf("Expected client version 800, got %d", entity.GetClientVersion())
|
|
}
|
|
|
|
// Test default name
|
|
entityNoName := &PlaceholderEntity{ID: 456}
|
|
expectedName := "Entity_456"
|
|
if entityNoName.GetName() != expectedName {
|
|
t.Errorf("Expected default name '%s', got '%s'", expectedName, entityNoName.GetName())
|
|
}
|
|
|
|
// Test default client version
|
|
entityNoVersion := &PlaceholderEntity{ID: 789}
|
|
if entityNoVersion.GetClientVersion() != 1000 {
|
|
t.Errorf("Expected default client version 1000, got %d", entityNoVersion.GetClientVersion())
|
|
}
|
|
}
|
|
|
|
func TestPlaceholderItem(t *testing.T) {
|
|
creationTime := time.Now()
|
|
item := &PlaceholderItem{
|
|
ID: 456,
|
|
Name: "Test Item",
|
|
Quantity: 10,
|
|
IconID: 789,
|
|
NoTradeFlag: false,
|
|
HeirloomFlag: true,
|
|
AttunedFlag: false,
|
|
CreatedTime: creationTime,
|
|
GroupIDs: []int32{1, 2, 3},
|
|
}
|
|
|
|
if item.GetID() != 456 {
|
|
t.Errorf("Expected ID 456, got %d", item.GetID())
|
|
}
|
|
|
|
if item.GetName() != "Test Item" {
|
|
t.Errorf("Expected name 'Test Item', got '%s'", item.GetName())
|
|
}
|
|
|
|
if item.GetQuantity() != 10 {
|
|
t.Errorf("Expected quantity 10, got %d", item.GetQuantity())
|
|
}
|
|
|
|
if item.GetIcon(1000) != 789 {
|
|
t.Errorf("Expected icon ID 789, got %d", item.GetIcon(1000))
|
|
}
|
|
|
|
if item.IsNoTrade() {
|
|
t.Error("Expected item not to be no-trade")
|
|
}
|
|
|
|
if !item.IsHeirloom() {
|
|
t.Error("Expected item to be heirloom")
|
|
}
|
|
|
|
if item.IsAttuned() {
|
|
t.Error("Expected item not to be attuned")
|
|
}
|
|
|
|
if !item.GetCreationTime().Equal(creationTime) {
|
|
t.Error("Expected creation time to match")
|
|
}
|
|
|
|
groupIDs := item.GetGroupCharacterIDs()
|
|
if len(groupIDs) != 3 || groupIDs[0] != 1 || groupIDs[1] != 2 || groupIDs[2] != 3 {
|
|
t.Errorf("Expected group IDs [1,2,3], got %v", groupIDs)
|
|
}
|
|
|
|
// Test default name
|
|
itemNoName := &PlaceholderItem{ID: 999}
|
|
expectedName := "Item_999"
|
|
if itemNoName.GetName() != expectedName {
|
|
t.Errorf("Expected default name '%s', got '%s'", expectedName, itemNoName.GetName())
|
|
}
|
|
}
|
|
|
|
// Test TradeParticipant
|
|
func TestNewTradeParticipant(t *testing.T) {
|
|
// Test legacy client
|
|
participant := NewTradeParticipant(123, false, 561)
|
|
if participant.EntityID != 123 {
|
|
t.Errorf("Expected entity ID 123, got %d", participant.EntityID)
|
|
}
|
|
if participant.IsBot != false {
|
|
t.Error("Expected participant not to be a bot")
|
|
}
|
|
if participant.MaxSlots != TradeMaxSlotsLegacy {
|
|
t.Errorf("Expected %d max slots, got %d", TradeMaxSlotsLegacy, participant.MaxSlots)
|
|
}
|
|
if participant.ClientVersion != 561 {
|
|
t.Errorf("Expected client version 561, got %d", participant.ClientVersion)
|
|
}
|
|
if participant.HasAccepted {
|
|
t.Error("Expected participant not to have accepted initially")
|
|
}
|
|
if len(participant.Items) != 0 {
|
|
t.Error("Expected empty items map initially")
|
|
}
|
|
if participant.Coins != 0 {
|
|
t.Error("Expected zero coins initially")
|
|
}
|
|
|
|
// Test modern client
|
|
participant2 := NewTradeParticipant(456, true, 1000)
|
|
if participant2.MaxSlots != TradeMaxSlotsDefault {
|
|
t.Errorf("Expected %d max slots, got %d", TradeMaxSlotsDefault, participant2.MaxSlots)
|
|
}
|
|
if participant2.IsBot != true {
|
|
t.Error("Expected participant to be a bot")
|
|
}
|
|
}
|
|
|
|
func TestTradeParticipantMethods(t *testing.T) {
|
|
participant := NewTradeParticipant(123, false, 1000)
|
|
|
|
// Test GetNextFreeSlot
|
|
slot := participant.GetNextFreeSlot()
|
|
if slot != 0 {
|
|
t.Errorf("Expected first free slot to be 0, got %d", slot)
|
|
}
|
|
|
|
// Add an item and test slot finding
|
|
testItem := &PlaceholderItem{ID: 100, Quantity: 5}
|
|
participant.Items[0] = TradeItemInfo{Item: testItem, Quantity: 5}
|
|
|
|
slot = participant.GetNextFreeSlot()
|
|
if slot != 1 {
|
|
t.Errorf("Expected next free slot to be 1, got %d", slot)
|
|
}
|
|
|
|
// Fill all slots
|
|
for i := int8(1); i < participant.MaxSlots; i++ {
|
|
participant.Items[i] = TradeItemInfo{Item: testItem, Quantity: 1}
|
|
}
|
|
|
|
slot = participant.GetNextFreeSlot()
|
|
if slot != int8(TradeSlotAutoFind) {
|
|
t.Errorf("Expected no free slots (%d), got %d", int8(TradeSlotAutoFind), slot)
|
|
}
|
|
|
|
// Test HasItem
|
|
if !participant.HasItem(100) {
|
|
t.Error("Expected participant to have item 100")
|
|
}
|
|
if participant.HasItem(999) {
|
|
t.Error("Expected participant not to have item 999")
|
|
}
|
|
|
|
// Test GetItemCount
|
|
expectedCount := int(participant.MaxSlots)
|
|
if participant.GetItemCount() != expectedCount {
|
|
t.Errorf("Expected %d items, got %d", expectedCount, participant.GetItemCount())
|
|
}
|
|
|
|
// Test ClearItems
|
|
participant.ClearItems()
|
|
if participant.GetItemCount() != 0 {
|
|
t.Error("Expected no items after clear")
|
|
}
|
|
|
|
// Test GetCoinAmounts
|
|
participant.Coins = 1234567
|
|
coinAmounts := participant.GetCoinAmounts()
|
|
expected := CalculateCoins(1234567)
|
|
if coinAmounts != expected {
|
|
t.Errorf("Expected coin amounts %+v, got %+v", expected, coinAmounts)
|
|
}
|
|
}
|
|
|
|
// Test TradeManager
|
|
func TestTradeManager(t *testing.T) {
|
|
tm := NewTradeManager()
|
|
|
|
if tm.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades initially")
|
|
}
|
|
|
|
// Create test entities
|
|
entity1 := &PlaceholderEntity{ID: 100, Name: "Player1"}
|
|
entity2 := &PlaceholderEntity{ID: 200, Name: "Player2"}
|
|
|
|
// Create a trade
|
|
trade := NewTrade(entity1, entity2)
|
|
if trade == nil {
|
|
t.Fatal("Failed to create trade")
|
|
}
|
|
|
|
// Add trade to manager
|
|
tm.AddTrade(trade)
|
|
|
|
if tm.GetActiveTradeCount() != 1 {
|
|
t.Error("Expected 1 active trade")
|
|
}
|
|
|
|
// Test GetTrade for trader1
|
|
retrievedTrade := tm.GetTrade(100)
|
|
if retrievedTrade == nil {
|
|
t.Error("Expected to find trade for entity 100")
|
|
}
|
|
if retrievedTrade.GetTrader1ID() != 100 {
|
|
t.Error("Expected trade with trader1 ID 100")
|
|
}
|
|
|
|
// Test GetTrade for trader2
|
|
retrievedTrade = tm.GetTrade(200)
|
|
if retrievedTrade == nil {
|
|
t.Error("Expected to find trade for entity 200")
|
|
}
|
|
if retrievedTrade.GetTrader2ID() != 200 {
|
|
t.Error("Expected trade with trader2 ID 200")
|
|
}
|
|
|
|
// Test GetTrade for non-participant
|
|
retrievedTrade = tm.GetTrade(999)
|
|
if retrievedTrade != nil {
|
|
t.Error("Expected no trade for entity 999")
|
|
}
|
|
|
|
// Remove trade
|
|
tm.RemoveTrade(100)
|
|
if tm.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after removal")
|
|
}
|
|
|
|
retrievedTrade = tm.GetTrade(100)
|
|
if retrievedTrade != nil {
|
|
t.Error("Expected no trade after removal")
|
|
}
|
|
}
|
|
|
|
// Test Trade creation and basic operations
|
|
func TestNewTrade(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100, Name: "Player1"}
|
|
entity2 := &PlaceholderEntity{ID: 200, Name: "Player2"}
|
|
|
|
// Valid trade creation
|
|
trade := NewTrade(entity1, entity2)
|
|
if trade == nil {
|
|
t.Fatal("Expected trade to be created")
|
|
}
|
|
|
|
if trade.GetTrader1ID() != 100 {
|
|
t.Errorf("Expected trader1 ID 100, got %d", trade.GetTrader1ID())
|
|
}
|
|
|
|
if trade.GetTrader2ID() != 200 {
|
|
t.Errorf("Expected trader2 ID 200, got %d", trade.GetTrader2ID())
|
|
}
|
|
|
|
if trade.GetState() != TradeStateActive {
|
|
t.Errorf("Expected trade state %d, got %d", TradeStateActive, trade.GetState())
|
|
}
|
|
|
|
// Test GetTradee
|
|
if trade.GetTradee(100) != 200 {
|
|
t.Error("Expected tradee of 100 to be 200")
|
|
}
|
|
if trade.GetTradee(200) != 100 {
|
|
t.Error("Expected tradee of 200 to be 100")
|
|
}
|
|
if trade.GetTradee(999) != 0 {
|
|
t.Error("Expected tradee of 999 to be 0")
|
|
}
|
|
|
|
// Test GetParticipant
|
|
participant := trade.GetParticipant(100)
|
|
if participant == nil {
|
|
t.Error("Expected to find participant 100")
|
|
}
|
|
if participant.EntityID != 100 {
|
|
t.Error("Expected participant entity ID 100")
|
|
}
|
|
|
|
participant = trade.GetParticipant(999)
|
|
if participant != nil {
|
|
t.Error("Expected not to find participant 999")
|
|
}
|
|
|
|
// Invalid trade creation
|
|
invalidTrade := NewTrade(nil, entity2)
|
|
if invalidTrade != nil {
|
|
t.Error("Expected trade creation to fail with nil entity")
|
|
}
|
|
|
|
invalidTrade = NewTrade(entity1, nil)
|
|
if invalidTrade != nil {
|
|
t.Error("Expected trade creation to fail with nil entity")
|
|
}
|
|
}
|
|
|
|
func TestTradeAddRemoveItems(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
testItem := &PlaceholderItem{
|
|
ID: 500,
|
|
Name: "Test Item",
|
|
Quantity: 10,
|
|
}
|
|
|
|
// Test adding item
|
|
err := trade.AddItemToTrade(100, testItem, 5, 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add item to trade: %v", err)
|
|
}
|
|
|
|
// Verify item was added
|
|
retrievedItem := trade.GetTraderSlot(100, 0)
|
|
if retrievedItem == nil {
|
|
t.Error("Expected to find item in slot 0")
|
|
}
|
|
if retrievedItem.GetID() != 500 {
|
|
t.Error("Expected item ID 500")
|
|
}
|
|
|
|
// Test auto-slot finding
|
|
testItem2 := &PlaceholderItem{ID: 501, Quantity: 3}
|
|
err = trade.AddItemToTrade(100, testItem2, 3, TradeSlotAutoFind)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add item with auto-slot: %v", err)
|
|
}
|
|
|
|
retrievedItem = trade.GetTraderSlot(100, 1)
|
|
if retrievedItem == nil {
|
|
t.Error("Expected to find item in slot 1")
|
|
}
|
|
|
|
// Test adding to occupied slot
|
|
err = trade.AddItemToTrade(100, testItem, 1, 0)
|
|
if err == nil {
|
|
t.Error("Expected error when adding to occupied slot")
|
|
}
|
|
|
|
// Test adding duplicate item
|
|
err = trade.AddItemToTrade(100, testItem, 1, 2)
|
|
if err == nil {
|
|
t.Error("Expected error when adding duplicate item")
|
|
}
|
|
|
|
// Test invalid slot
|
|
err = trade.AddItemToTrade(100, testItem, 1, 99)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid slot")
|
|
}
|
|
|
|
// Test insufficient quantity
|
|
err = trade.AddItemToTrade(100, testItem, 20, 3)
|
|
if err == nil {
|
|
t.Error("Expected error for insufficient quantity")
|
|
}
|
|
|
|
// Test invalid entity
|
|
err = trade.AddItemToTrade(999, testItem, 1, 4)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid entity")
|
|
}
|
|
|
|
// Test removing item
|
|
err = trade.RemoveItemFromTrade(100, 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove item: %v", err)
|
|
}
|
|
|
|
retrievedItem = trade.GetTraderSlot(100, 0)
|
|
if retrievedItem != nil {
|
|
t.Error("Expected item to be removed from slot 0")
|
|
}
|
|
|
|
// Test removing from empty slot
|
|
err = trade.RemoveItemFromTrade(100, 0)
|
|
if err == nil {
|
|
t.Error("Expected error when removing from empty slot")
|
|
}
|
|
|
|
// Test no-trade item
|
|
noTradeItem := &PlaceholderItem{
|
|
ID: 600,
|
|
Quantity: 5,
|
|
NoTradeFlag: true,
|
|
}
|
|
err = trade.AddItemToTrade(100, noTradeItem, 5, 0)
|
|
if err == nil {
|
|
t.Error("Expected error for no-trade item")
|
|
}
|
|
|
|
// Test attuned heirloom item
|
|
attunedHeirloom := &PlaceholderItem{
|
|
ID: 700,
|
|
Quantity: 1,
|
|
HeirloomFlag: true,
|
|
AttunedFlag: true,
|
|
}
|
|
err = trade.AddItemToTrade(100, attunedHeirloom, 1, 0)
|
|
if err == nil {
|
|
t.Error("Expected error for attuned heirloom item")
|
|
}
|
|
|
|
// Test expired heirloom item
|
|
expiredHeirloom := &PlaceholderItem{
|
|
ID: 701,
|
|
Quantity: 1,
|
|
HeirloomFlag: true,
|
|
AttunedFlag: false,
|
|
CreatedTime: time.Now().Add(-72 * time.Hour), // 3 days ago
|
|
}
|
|
err = trade.AddItemToTrade(100, expiredHeirloom, 1, 0)
|
|
if err == nil {
|
|
t.Error("Expected error for expired heirloom item")
|
|
}
|
|
|
|
// Test valid recent heirloom item
|
|
recentHeirloom := &PlaceholderItem{
|
|
ID: 702,
|
|
Quantity: 1,
|
|
HeirloomFlag: true,
|
|
AttunedFlag: false,
|
|
CreatedTime: time.Now().Add(-1 * time.Hour), // 1 hour ago
|
|
}
|
|
err = trade.AddItemToTrade(100, recentHeirloom, 1, 0)
|
|
if err != nil {
|
|
t.Errorf("Expected recent heirloom item to be tradeable: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestTradeCoins(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Test adding coins
|
|
err := trade.AddCoinsToTrade(100, 5000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add coins to trade: %v", err)
|
|
}
|
|
|
|
participant := trade.GetParticipant(100)
|
|
if participant.Coins != 5000 {
|
|
t.Errorf("Expected 5000 coins, got %d", participant.Coins)
|
|
}
|
|
|
|
// Test adding more coins
|
|
err = trade.AddCoinsToTrade(100, 2000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add more coins: %v", err)
|
|
}
|
|
|
|
if participant.Coins != 7000 {
|
|
t.Errorf("Expected 7000 coins, got %d", participant.Coins)
|
|
}
|
|
|
|
// Test removing coins
|
|
err = trade.RemoveCoinsFromTrade(100, 3000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove coins: %v", err)
|
|
}
|
|
|
|
if participant.Coins != 4000 {
|
|
t.Errorf("Expected 4000 coins, got %d", participant.Coins)
|
|
}
|
|
|
|
// Test removing more coins than available
|
|
err = trade.RemoveCoinsFromTrade(100, 10000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove excess coins: %v", err)
|
|
}
|
|
|
|
if participant.Coins != 0 {
|
|
t.Errorf("Expected 0 coins, got %d", participant.Coins)
|
|
}
|
|
|
|
// Test invalid coin amount
|
|
err = trade.AddCoinsToTrade(100, -100)
|
|
if err == nil {
|
|
t.Error("Expected error for negative coin amount")
|
|
}
|
|
|
|
err = trade.AddCoinsToTrade(100, 0)
|
|
if err == nil {
|
|
t.Error("Expected error for zero coin amount")
|
|
}
|
|
|
|
// Test invalid entity
|
|
err = trade.AddCoinsToTrade(999, 1000)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid entity")
|
|
}
|
|
}
|
|
|
|
func TestTradeAcceptance(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Initially, neither should have accepted
|
|
if trade.HasAcceptedTrade(100) {
|
|
t.Error("Expected trader1 not to have accepted initially")
|
|
}
|
|
if trade.HasAcceptedTrade(200) {
|
|
t.Error("Expected trader2 not to have accepted initially")
|
|
}
|
|
if trade.HasAcceptedTrade(999) {
|
|
t.Error("Expected invalid entity not to have accepted")
|
|
}
|
|
|
|
// First trader accepts
|
|
completed, err := trade.SetTradeAccepted(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to set trade accepted: %v", err)
|
|
}
|
|
if completed {
|
|
t.Error("Expected trade not to be completed after one acceptance")
|
|
}
|
|
|
|
if !trade.HasAcceptedTrade(100) {
|
|
t.Error("Expected trader1 to have accepted")
|
|
}
|
|
if trade.HasAcceptedTrade(200) {
|
|
t.Error("Expected trader2 not to have accepted yet")
|
|
}
|
|
|
|
// Second trader accepts - should complete
|
|
completed, err = trade.SetTradeAccepted(200)
|
|
if err != nil {
|
|
t.Fatalf("Failed to set second trade accepted: %v", err)
|
|
}
|
|
if !completed {
|
|
t.Error("Expected trade to be completed after both acceptances")
|
|
}
|
|
|
|
if trade.GetState() != TradeStateCompleted {
|
|
t.Errorf("Expected trade state %d, got %d", TradeStateCompleted, trade.GetState())
|
|
}
|
|
|
|
// Test accepting invalid entity
|
|
_, err = trade.SetTradeAccepted(999)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid entity acceptance")
|
|
}
|
|
}
|
|
|
|
func TestTradeCancel(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Cancel trade
|
|
err := trade.CancelTrade(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to cancel trade: %v", err)
|
|
}
|
|
|
|
if trade.GetState() != TradeStateCanceled {
|
|
t.Errorf("Expected trade state %d, got %d", TradeStateCanceled, trade.GetState())
|
|
}
|
|
|
|
// Test operations on canceled trade
|
|
testItem := &PlaceholderItem{ID: 500, Quantity: 5}
|
|
err = trade.AddItemToTrade(100, testItem, 5, 0)
|
|
if err == nil {
|
|
t.Error("Expected error adding item to canceled trade")
|
|
}
|
|
|
|
err = trade.AddCoinsToTrade(100, 1000)
|
|
if err == nil {
|
|
t.Error("Expected error adding coins to canceled trade")
|
|
}
|
|
|
|
_, err = trade.SetTradeAccepted(100)
|
|
if err == nil {
|
|
t.Error("Expected error accepting canceled trade")
|
|
}
|
|
}
|
|
|
|
func TestTradeStateChangesResetAcceptance(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Both traders accept
|
|
trade.SetTradeAccepted(100)
|
|
trade.SetTradeAccepted(200) // This completes the trade
|
|
|
|
// Create new trade for testing reset behavior
|
|
trade2 := NewTrade(entity1, entity2)
|
|
|
|
// First trader accepts
|
|
trade2.SetTradeAccepted(100)
|
|
if !trade2.HasAcceptedTrade(100) {
|
|
t.Error("Expected trader1 to have accepted")
|
|
}
|
|
|
|
// Add item - should reset acceptance
|
|
testItem := &PlaceholderItem{ID: 500, Quantity: 5}
|
|
err := trade2.AddItemToTrade(100, testItem, 5, 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add item: %v", err)
|
|
}
|
|
|
|
if trade2.HasAcceptedTrade(100) {
|
|
t.Error("Expected acceptance to be reset after adding item")
|
|
}
|
|
|
|
// Accept again and add coins - should reset
|
|
trade2.SetTradeAccepted(100)
|
|
err = trade2.AddCoinsToTrade(100, 1000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add coins: %v", err)
|
|
}
|
|
|
|
if trade2.HasAcceptedTrade(100) {
|
|
t.Error("Expected acceptance to be reset after adding coins")
|
|
}
|
|
|
|
// Accept again and remove item - should reset
|
|
trade2.SetTradeAccepted(100)
|
|
err = trade2.RemoveItemFromTrade(100, 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove item: %v", err)
|
|
}
|
|
|
|
if trade2.HasAcceptedTrade(100) {
|
|
t.Error("Expected acceptance to be reset after removing item")
|
|
}
|
|
|
|
// Accept again and remove coins - should reset
|
|
trade2.SetTradeAccepted(100)
|
|
err = trade2.RemoveCoinsFromTrade(100, 500)
|
|
if err != nil {
|
|
t.Fatalf("Failed to remove coins: %v", err)
|
|
}
|
|
|
|
if trade2.HasAcceptedTrade(100) {
|
|
t.Error("Expected acceptance to be reset after removing coins")
|
|
}
|
|
}
|
|
|
|
func TestGetTradeInfo(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Add some items and coins
|
|
testItem := &PlaceholderItem{ID: 500, Quantity: 5}
|
|
trade.AddItemToTrade(100, testItem, 5, 0)
|
|
trade.AddCoinsToTrade(200, 10000)
|
|
|
|
info := trade.GetTradeInfo()
|
|
|
|
if info["state"] != TradeStateActive {
|
|
t.Error("Expected trade state to be active")
|
|
}
|
|
if info["trader1_id"] != int32(100) {
|
|
t.Error("Expected trader1_id to be 100")
|
|
}
|
|
if info["trader2_id"] != int32(200) {
|
|
t.Error("Expected trader2_id to be 200")
|
|
}
|
|
if info["trader1_items"] != 1 {
|
|
t.Error("Expected trader1 to have 1 item")
|
|
}
|
|
if info["trader2_items"] != 0 {
|
|
t.Error("Expected trader2 to have 0 items")
|
|
}
|
|
if info["trader1_coins"] != int64(0) {
|
|
t.Error("Expected trader1 to have 0 coins")
|
|
}
|
|
if info["trader2_coins"] != int64(10000) {
|
|
t.Error("Expected trader2 to have 10000 coins")
|
|
}
|
|
if info["trader1_accepted"] != false {
|
|
t.Error("Expected trader1 not to have accepted")
|
|
}
|
|
if info["trader2_accepted"] != false {
|
|
t.Error("Expected trader2 not to have accepted")
|
|
}
|
|
|
|
// Test after acceptance
|
|
trade.SetTradeAccepted(100)
|
|
info = trade.GetTradeInfo()
|
|
if info["trader1_accepted"] != true {
|
|
t.Error("Expected trader1 to have accepted")
|
|
}
|
|
}
|
|
|
|
// Test TradeService
|
|
func TestTradeService(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades initially")
|
|
}
|
|
|
|
// Test InitiateTrade
|
|
trade, err := service.InitiateTrade(100, 200)
|
|
if err != nil {
|
|
t.Fatalf("Failed to initiate trade: %v", err)
|
|
}
|
|
if trade == nil {
|
|
t.Fatal("Expected trade to be created")
|
|
}
|
|
|
|
if service.GetActiveTradeCount() != 1 {
|
|
t.Error("Expected 1 active trade")
|
|
}
|
|
|
|
// Test duplicate trade initiation
|
|
_, err = service.InitiateTrade(100, 300)
|
|
if err == nil {
|
|
t.Error("Expected error when initiating duplicate trade")
|
|
}
|
|
|
|
_, err = service.InitiateTrade(300, 200)
|
|
if err == nil {
|
|
t.Error("Expected error when target is already in trade")
|
|
}
|
|
|
|
// Test GetTrade
|
|
retrievedTrade := service.GetTrade(100)
|
|
if retrievedTrade == nil {
|
|
t.Error("Expected to find trade")
|
|
}
|
|
|
|
// Test service operations
|
|
testItem := &PlaceholderItem{ID: 500, Quantity: 10}
|
|
err = service.AddItemToTrade(100, testItem, 5, 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add item via service: %v", err)
|
|
}
|
|
|
|
err = service.AddCoinsToTrade(200, 5000)
|
|
if err != nil {
|
|
t.Fatalf("Failed to add coins via service: %v", err)
|
|
}
|
|
|
|
// Test GetTradeInfo
|
|
info, err := service.GetTradeInfo(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get trade info: %v", err)
|
|
}
|
|
if info["trader1_items"] != 1 {
|
|
t.Error("Expected 1 item in trade info")
|
|
}
|
|
|
|
// Test AcceptTrade
|
|
completed, err := service.AcceptTrade(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to accept trade: %v", err)
|
|
}
|
|
if completed {
|
|
t.Error("Expected trade not to be completed yet")
|
|
}
|
|
|
|
completed, err = service.AcceptTrade(200)
|
|
if err != nil {
|
|
t.Fatalf("Failed to accept trade for second trader: %v", err)
|
|
}
|
|
if !completed {
|
|
t.Error("Expected trade to be completed")
|
|
}
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after completion")
|
|
}
|
|
}
|
|
|
|
func TestTradeServiceValidation(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
// Test ValidateTradeRequest
|
|
err := service.ValidateTradeRequest(100, 100)
|
|
if err == nil {
|
|
t.Error("Expected error for self-trade")
|
|
}
|
|
|
|
err = service.ValidateTradeRequest(0, 100)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid initiator ID")
|
|
}
|
|
|
|
err = service.ValidateTradeRequest(100, -1)
|
|
if err == nil {
|
|
t.Error("Expected error for invalid target ID")
|
|
}
|
|
|
|
// Valid request
|
|
err = service.ValidateTradeRequest(100, 200)
|
|
if err != nil {
|
|
t.Errorf("Expected valid trade request: %v", err)
|
|
}
|
|
|
|
// After creating trade, validation should fail
|
|
service.InitiateTrade(100, 200)
|
|
err = service.ValidateTradeRequest(100, 300)
|
|
if err == nil {
|
|
t.Error("Expected error for already trading initiator")
|
|
}
|
|
|
|
err = service.ValidateTradeRequest(300, 200)
|
|
if err == nil {
|
|
t.Error("Expected error for already trading target")
|
|
}
|
|
}
|
|
|
|
func TestTradeServiceCancel(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
trade, _ := service.InitiateTrade(100, 200)
|
|
if trade == nil {
|
|
t.Fatal("Failed to create trade")
|
|
}
|
|
|
|
err := service.CancelTrade(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to cancel trade: %v", err)
|
|
}
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after cancellation")
|
|
}
|
|
|
|
// Test canceling non-existent trade
|
|
err = service.CancelTrade(999)
|
|
if err == nil {
|
|
t.Error("Expected error canceling non-existent trade")
|
|
}
|
|
}
|
|
|
|
func TestTradeServiceAdminFunctions(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
trade, _ := service.InitiateTrade(100, 200)
|
|
if trade == nil {
|
|
t.Fatal("Failed to create trade")
|
|
}
|
|
|
|
// Test ForceCompleteTrade
|
|
err := service.ForceCompleteTrade(100)
|
|
if err != nil {
|
|
t.Fatalf("Failed to force complete trade: %v", err)
|
|
}
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after forced completion")
|
|
}
|
|
|
|
// Test ForceCancelTrade
|
|
trade2, _ := service.InitiateTrade(300, 400)
|
|
if trade2 == nil {
|
|
t.Fatal("Failed to create second trade")
|
|
}
|
|
|
|
err = service.ForceCancelTrade(300, "Admin intervention")
|
|
if err != nil {
|
|
t.Fatalf("Failed to force cancel trade: %v", err)
|
|
}
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after forced cancellation")
|
|
}
|
|
}
|
|
|
|
func TestTradeServiceStatistics(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
stats := service.GetTradeStatistics()
|
|
if stats["active_trades"] != 0 {
|
|
t.Error("Expected 0 active trades in statistics")
|
|
}
|
|
|
|
if stats["max_trade_duration_minutes"] != float64(30) {
|
|
t.Error("Expected 30 minute max duration")
|
|
}
|
|
|
|
// Create some trades
|
|
service.InitiateTrade(100, 200)
|
|
service.InitiateTrade(300, 400)
|
|
|
|
stats = service.GetTradeStatistics()
|
|
if stats["active_trades"] != 2 {
|
|
t.Error("Expected 2 active trades in statistics")
|
|
}
|
|
}
|
|
|
|
func TestTradeServiceShutdown(t *testing.T) {
|
|
service := NewTradeService()
|
|
|
|
service.InitiateTrade(100, 200)
|
|
service.InitiateTrade(300, 400)
|
|
|
|
if service.GetActiveTradeCount() != 2 {
|
|
t.Fatal("Expected 2 active trades before shutdown")
|
|
}
|
|
|
|
service.Shutdown()
|
|
|
|
if service.GetActiveTradeCount() != 0 {
|
|
t.Error("Expected no active trades after shutdown")
|
|
}
|
|
}
|
|
|
|
// Test concurrent access
|
|
func TestTradeConcurrency(t *testing.T) {
|
|
service := NewTradeService()
|
|
trade, _ := service.InitiateTrade(100, 200)
|
|
|
|
var wg sync.WaitGroup
|
|
numGoroutines := 10
|
|
numOperations := 100
|
|
|
|
// Test concurrent coin operations
|
|
wg.Add(numGoroutines)
|
|
for i := 0; i < numGoroutines; i++ {
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
for j := 0; j < numOperations; j++ {
|
|
if j%2 == 0 {
|
|
trade.AddCoinsToTrade(100, 100)
|
|
} else {
|
|
trade.RemoveCoinsFromTrade(100, 50)
|
|
}
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// Verify trade is still in valid state
|
|
if trade.GetState() != TradeStateActive {
|
|
t.Error("Expected trade to remain active after concurrent operations")
|
|
}
|
|
|
|
info := trade.GetTradeInfo()
|
|
if info == nil {
|
|
t.Error("Expected to get trade info after concurrent operations")
|
|
}
|
|
}
|
|
|
|
// Test utility functions
|
|
func TestCompareTradeItems(t *testing.T) {
|
|
item1 := &PlaceholderItem{ID: 100}
|
|
item2 := &PlaceholderItem{ID: 200}
|
|
|
|
tradeItem1 := TradeItemInfo{Item: item1, Quantity: 5}
|
|
tradeItem2 := TradeItemInfo{Item: item1, Quantity: 5}
|
|
tradeItem3 := TradeItemInfo{Item: item2, Quantity: 5}
|
|
tradeItem4 := TradeItemInfo{Item: item1, Quantity: 10}
|
|
|
|
// Test equal items
|
|
if !CompareTradeItems(tradeItem1, tradeItem2) {
|
|
t.Error("Expected items to be equal")
|
|
}
|
|
|
|
// Test different items
|
|
if CompareTradeItems(tradeItem1, tradeItem3) {
|
|
t.Error("Expected items to be different (different item)")
|
|
}
|
|
|
|
// Test different quantities
|
|
if CompareTradeItems(tradeItem1, tradeItem4) {
|
|
t.Error("Expected items to be different (different quantity)")
|
|
}
|
|
|
|
// Test nil items
|
|
nilItem1 := TradeItemInfo{Item: nil, Quantity: 5}
|
|
nilItem2 := TradeItemInfo{Item: nil, Quantity: 5}
|
|
nilItem3 := TradeItemInfo{Item: nil, Quantity: 10}
|
|
|
|
if !CompareTradeItems(nilItem1, nilItem2) {
|
|
t.Error("Expected nil items with same quantity to be equal")
|
|
}
|
|
|
|
if CompareTradeItems(nilItem1, nilItem3) {
|
|
t.Error("Expected nil items with different quantity to be different")
|
|
}
|
|
|
|
if CompareTradeItems(nilItem1, tradeItem1) {
|
|
t.Error("Expected nil item and real item to be different")
|
|
}
|
|
}
|
|
|
|
func TestCalculateTradeValue(t *testing.T) {
|
|
participant := NewTradeParticipant(123, false, 1000)
|
|
participant.Coins = 50000
|
|
|
|
item1 := &PlaceholderItem{ID: 100, Name: "Sword"}
|
|
item2 := &PlaceholderItem{ID: 200, Name: "Shield"}
|
|
|
|
participant.Items[0] = TradeItemInfo{Item: item1, Quantity: 1}
|
|
participant.Items[1] = TradeItemInfo{Item: item2, Quantity: 2}
|
|
|
|
value := CalculateTradeValue(participant)
|
|
|
|
if value["coins"] != int64(50000) {
|
|
t.Error("Expected coins value to be 50000")
|
|
}
|
|
|
|
coinsFormatted, ok := value["coins_formatted"].(string)
|
|
if !ok || coinsFormatted != "5 gold" {
|
|
t.Errorf("Expected coins_formatted to be '5 gold', got %v", coinsFormatted)
|
|
}
|
|
|
|
if value["item_count"] != 2 {
|
|
t.Error("Expected item count to be 2")
|
|
}
|
|
|
|
items, ok := value["items"].([]map[string]any)
|
|
if !ok || len(items) != 2 {
|
|
t.Error("Expected items array with 2 elements")
|
|
}
|
|
|
|
// Verify item data (order may vary due to map iteration)
|
|
foundSword := false
|
|
foundShield := false
|
|
for _, item := range items {
|
|
if item["item_name"] == "Sword" {
|
|
foundSword = true
|
|
if item["quantity"] != int32(1) {
|
|
t.Error("Expected sword quantity to be 1")
|
|
}
|
|
}
|
|
if item["item_name"] == "Shield" {
|
|
foundShield = true
|
|
if item["quantity"] != int32(2) {
|
|
t.Error("Expected shield quantity to be 2")
|
|
}
|
|
}
|
|
}
|
|
|
|
if !foundSword || !foundShield {
|
|
t.Error("Expected to find both sword and shield in items")
|
|
}
|
|
}
|
|
|
|
func TestValidateTradeCompletion(t *testing.T) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
// Test validation with no acceptance
|
|
errors := ValidateTradeCompletion(trade)
|
|
expectedErrors := 2 // Neither trader has accepted
|
|
if len(errors) != expectedErrors {
|
|
t.Errorf("Expected %d errors, got %d: %v", expectedErrors, len(errors), errors)
|
|
}
|
|
|
|
// Test validation with one acceptance
|
|
trade.SetTradeAccepted(100)
|
|
errors = ValidateTradeCompletion(trade)
|
|
expectedErrors = 1 // Only trader2 hasn't accepted
|
|
if len(errors) != expectedErrors {
|
|
t.Errorf("Expected %d errors, got %d: %v", expectedErrors, len(errors), errors)
|
|
}
|
|
|
|
// Test validation with both acceptances
|
|
trade.SetTradeAccepted(200) // This completes the trade
|
|
|
|
// Create new trade for testing completed state validation
|
|
completedTrade := NewTrade(entity1, entity2)
|
|
completedTrade.SetTradeAccepted(100)
|
|
completedTrade.SetTradeAccepted(200) // This marks as completed
|
|
|
|
errors = ValidateTradeCompletion(completedTrade)
|
|
expectedErrors = 1 // Trade is not in active state
|
|
if len(errors) != expectedErrors {
|
|
t.Errorf("Expected %d errors for completed trade, got %d: %v", expectedErrors, len(errors), errors)
|
|
}
|
|
}
|
|
|
|
func TestGenerateTradeLogEntry(t *testing.T) {
|
|
tradeID := "trade_123"
|
|
operation := "add_item"
|
|
entityID := int32(456)
|
|
details := map[string]any{"item_id": 789, "quantity": 5}
|
|
|
|
logEntry := GenerateTradeLogEntry(tradeID, operation, entityID, details)
|
|
expected := "[Trade:trade_123] add_item by entity 456: map[item_id:789 quantity:5]"
|
|
|
|
if logEntry != expected {
|
|
t.Errorf("Expected log entry '%s', got '%s'", expected, logEntry)
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkCalculateCoins(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
CalculateCoins(1234567)
|
|
}
|
|
}
|
|
|
|
func BenchmarkTradeCreation(b *testing.B) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
trade := NewTrade(entity1, entity2)
|
|
_ = trade
|
|
}
|
|
}
|
|
|
|
func BenchmarkTradeItemOperations(b *testing.B) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
item := &PlaceholderItem{ID: 500, Quantity: 100}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
slot := int8(i % int(TradeMaxSlotsDefault))
|
|
trade.AddItemToTrade(100, item, 1, slot)
|
|
trade.RemoveItemFromTrade(100, slot)
|
|
}
|
|
}
|
|
|
|
func BenchmarkTradeCoinOperations(b *testing.B) {
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
trade := NewTrade(entity1, entity2)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
trade.AddCoinsToTrade(100, 1000)
|
|
trade.RemoveCoinsFromTrade(100, 500)
|
|
}
|
|
}
|
|
|
|
func BenchmarkTradeManagerOperations(b *testing.B) {
|
|
tm := NewTradeManager()
|
|
entity1 := &PlaceholderEntity{ID: 100}
|
|
entity2 := &PlaceholderEntity{ID: 200}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
trade := NewTrade(entity1, entity2)
|
|
tm.AddTrade(trade)
|
|
tm.GetTrade(100)
|
|
tm.RemoveTrade(100)
|
|
}
|
|
} |