eq2go/internal/entity/info_struct_test.go

515 lines
13 KiB
Go

package entity
import (
"sync"
"testing"
"time"
)
func TestNewInfoStruct(t *testing.T) {
info := NewInfoStruct()
if info == nil {
t.Fatal("NewInfoStruct returned nil")
}
// Test default values
if info.GetName() != "" {
t.Errorf("Expected empty name, got %s", info.GetName())
}
if info.GetLevel() != 0 {
t.Errorf("Expected level 0, got %d", info.GetLevel())
}
if info.GetMaxConcentration() != 5 {
t.Errorf("Expected max concentration 5, got %d", info.GetMaxConcentration())
}
if info.GetCurConcentration() != 0 {
t.Errorf("Expected current concentration 0, got %d", info.GetCurConcentration())
}
}
func TestInfoStructBasicProperties(t *testing.T) {
info := NewInfoStruct()
// Test name
info.SetName("Test Character")
if info.GetName() != "Test Character" {
t.Errorf("Expected name 'Test Character', got %s", info.GetName())
}
// Test level
info.SetLevel(25)
if info.GetLevel() != 25 {
t.Errorf("Expected level 25, got %d", info.GetLevel())
}
// Test effective level
info.SetEffectiveLevel(30)
if info.GetEffectiveLevel() != 30 {
t.Errorf("Expected effective level 30, got %d", info.GetEffectiveLevel())
}
// Test class
info.SetClass1(5)
if info.GetClass1() != 5 {
t.Errorf("Expected class 5, got %d", info.GetClass1())
}
// Test race
info.SetRace(3)
if info.GetRace() != 3 {
t.Errorf("Expected race 3, got %d", info.GetRace())
}
// Test gender
info.SetGender(1)
if info.GetGender() != 1 {
t.Errorf("Expected gender 1, got %d", info.GetGender())
}
}
func TestInfoStructStats(t *testing.T) {
info := NewInfoStruct()
// Test strength
info.SetStr(15.5)
if info.GetStr() != 15.5 {
t.Errorf("Expected strength 15.5, got %f", info.GetStr())
}
// Test stamina
info.SetSta(20.0)
if info.GetSta() != 20.0 {
t.Errorf("Expected stamina 20.0, got %f", info.GetSta())
}
// Test agility
info.SetAgi(12.75)
if info.GetAgi() != 12.75 {
t.Errorf("Expected agility 12.75, got %f", info.GetAgi())
}
// Test wisdom
info.SetWis(18.25)
if info.GetWis() != 18.25 {
t.Errorf("Expected wisdom 18.25, got %f", info.GetWis())
}
// Test intelligence
info.SetIntel(22.5)
if info.GetIntel() != 22.5 {
t.Errorf("Expected intelligence 22.5, got %f", info.GetIntel())
}
}
func TestInfoStructConcentration(t *testing.T) {
info := NewInfoStruct()
// Test setting max concentration
info.SetMaxConcentration(15)
if info.GetMaxConcentration() != 15 {
t.Errorf("Expected max concentration 15, got %d", info.GetMaxConcentration())
}
// Test adding concentration
success := info.AddConcentration(5)
if !success {
t.Error("Expected AddConcentration to succeed")
}
if info.GetCurConcentration() != 5 {
t.Errorf("Expected current concentration 5, got %d", info.GetCurConcentration())
}
// Test adding concentration that would exceed maximum
success = info.AddConcentration(12)
if success {
t.Error("Expected AddConcentration to fail when exceeding maximum")
}
if info.GetCurConcentration() != 5 {
t.Errorf("Expected current concentration to remain 5, got %d", info.GetCurConcentration())
}
// Test adding concentration that exactly reaches maximum
success = info.AddConcentration(10)
if !success {
t.Error("Expected AddConcentration to succeed when exactly reaching maximum")
}
if info.GetCurConcentration() != 15 {
t.Errorf("Expected current concentration 15, got %d", info.GetCurConcentration())
}
// Test removing concentration
info.RemoveConcentration(7)
if info.GetCurConcentration() != 8 {
t.Errorf("Expected current concentration 8, got %d", info.GetCurConcentration())
}
// Test removing more concentration than available
info.RemoveConcentration(20)
if info.GetCurConcentration() != 0 {
t.Errorf("Expected current concentration to be clamped to 0, got %d", info.GetCurConcentration())
}
}
func TestInfoStructCoins(t *testing.T) {
info := NewInfoStruct()
// Test initial coins
if info.GetCoins() != 0 {
t.Errorf("Expected initial coins 0, got %d", info.GetCoins())
}
// Test adding copper
info.AddCoins(150) // 1 silver and 50 copper
totalCopper := info.GetCoins()
if totalCopper != 150 {
t.Errorf("Expected total coins 150, got %d", totalCopper)
}
// Test adding large amount that converts to higher denominations
info.AddCoins(1234567) // Should convert to plat, gold, silver, copper
expectedTotal := 150 + 1234567
totalCopper = info.GetCoins()
if totalCopper != int32(expectedTotal) {
t.Errorf("Expected total coins %d, got %d", expectedTotal, totalCopper)
}
// Test removing coins
success := info.RemoveCoins(100)
if !success {
t.Error("Expected RemoveCoins to succeed")
}
expectedTotal -= 100
totalCopper = info.GetCoins()
if totalCopper != int32(expectedTotal) {
t.Errorf("Expected total coins %d after removal, got %d", expectedTotal, totalCopper)
}
// Test removing more coins than available
success = info.RemoveCoins(9999999)
if success {
t.Error("Expected RemoveCoins to fail when removing more than available")
}
// Total should remain unchanged
totalCopper = info.GetCoins()
if totalCopper != int32(expectedTotal) {
t.Errorf("Expected total coins to remain %d, got %d", expectedTotal, totalCopper)
}
}
func TestInfoStructResistances(t *testing.T) {
info := NewInfoStruct()
// Test all resistance types
resistanceTypes := []string{"heat", "cold", "magic", "mental", "divine", "disease", "poison"}
expectedValues := []int16{10, 15, 20, 25, 30, 35, 40}
for i, resistType := range resistanceTypes {
expectedValue := expectedValues[i]
// Set resistance
info.SetResistance(resistType, expectedValue)
// Get resistance
actualValue := info.GetResistance(resistType)
if actualValue != expectedValue {
t.Errorf("Expected %s resistance %d, got %d", resistType, expectedValue, actualValue)
}
}
// Test invalid resistance type
unknownResist := info.GetResistance("unknown")
if unknownResist != 0 {
t.Errorf("Expected unknown resistance type to return 0, got %d", unknownResist)
}
// Setting invalid resistance type should not panic
info.SetResistance("unknown", 50) // Should be ignored
}
func TestInfoStructResetEffects(t *testing.T) {
info := NewInfoStruct()
// Set some base values first (these would normally be set during character creation)
info.str = 10.0
info.strBase = 10.0
info.sta = 12.0
info.staBase = 12.0
info.heat = 15
info.heatBase = 15
// Modify current values to simulate bonuses
info.SetStr(20.0)
info.SetSta(25.0)
info.SetResistance("heat", 30)
// Reset effects
info.ResetEffects()
// Check that values were reset to base
if info.GetStr() != 10.0 {
t.Errorf("Expected strength to reset to 10.0, got %f", info.GetStr())
}
if info.GetSta() != 12.0 {
t.Errorf("Expected stamina to reset to 12.0, got %f", info.GetSta())
}
if info.GetResistance("heat") != 15 {
t.Errorf("Expected heat resistance to reset to 15, got %d", info.GetResistance("heat"))
}
}
func TestInfoStructCalculatePrimaryStat(t *testing.T) {
info := NewInfoStruct()
// Set all stats to different values
info.SetStr(10.0)
info.SetSta(15.0)
info.SetAgi(8.0)
info.SetWis(20.0) // This should be the highest
info.SetIntel(12.0)
primaryStat := info.CalculatePrimaryStat()
if primaryStat != 20.0 {
t.Errorf("Expected primary stat 20.0 (wisdom), got %f", primaryStat)
}
// Test with intelligence being highest
info.SetIntel(25.0)
primaryStat = info.CalculatePrimaryStat()
if primaryStat != 25.0 {
t.Errorf("Expected primary stat 25.0 (intelligence), got %f", primaryStat)
}
// Test with all stats equal
info.SetStr(30.0)
info.SetSta(30.0)
info.SetAgi(30.0)
info.SetWis(30.0)
info.SetIntel(30.0)
primaryStat = info.CalculatePrimaryStat()
if primaryStat != 30.0 {
t.Errorf("Expected primary stat 30.0 (all equal), got %f", primaryStat)
}
}
func TestInfoStructClone(t *testing.T) {
info := NewInfoStruct()
// Set some values
info.SetName("Original Character")
info.SetLevel(15)
info.SetStr(20.0)
info.SetResistance("magic", 25)
info.AddConcentration(3)
// Clone the info struct
clone := info.Clone()
if clone == nil {
t.Fatal("Clone returned nil")
}
// Verify clone has same values
if clone.GetName() != "Original Character" {
t.Errorf("Expected cloned name 'Original Character', got %s", clone.GetName())
}
if clone.GetLevel() != 15 {
t.Errorf("Expected cloned level 15, got %d", clone.GetLevel())
}
if clone.GetStr() != 20.0 {
t.Errorf("Expected cloned strength 20.0, got %f", clone.GetStr())
}
if clone.GetResistance("magic") != 25 {
t.Errorf("Expected cloned magic resistance 25, got %d", clone.GetResistance("magic"))
}
if clone.GetCurConcentration() != 3 {
t.Errorf("Expected cloned concentration 3, got %d", clone.GetCurConcentration())
}
// Verify that modifying the clone doesn't affect the original
clone.SetName("Cloned Character")
clone.SetLevel(20)
if info.GetName() != "Original Character" {
t.Error("Original name was modified when clone was changed")
}
if info.GetLevel() != 15 {
t.Error("Original level was modified when clone was changed")
}
}
func TestInfoStructGetUptime(t *testing.T) {
info := NewInfoStruct()
// Test uptime (currently returns 0 as it's not implemented)
uptime := info.GetUptime()
if uptime != time.Duration(0) {
t.Errorf("Expected uptime to be 0 (not implemented), got %v", uptime)
}
}
func TestInfoStructConcurrency(t *testing.T) {
info := NewInfoStruct()
info.SetMaxConcentration(100)
var wg sync.WaitGroup
numGoroutines := 20
// Test concurrent access to basic properties
wg.Add(numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func(index int) {
defer wg.Done()
// Each goroutine sets unique values
info.SetName("Character" + string(rune('A'+index)))
_ = info.GetName()
info.SetLevel(int16(10 + index))
_ = info.GetLevel()
info.SetStr(float32(10.0 + float32(index)))
_ = info.GetStr()
}(i)
}
wg.Wait()
// Test concurrent concentration operations
wg.Add(numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func() {
defer wg.Done()
// Try to add concentration
if info.AddConcentration(1) {
// If successful, remove it after a short delay
time.Sleep(time.Microsecond)
info.RemoveConcentration(1)
}
}()
}
wg.Wait()
// After all operations, concentration should be back to 0
// (This might not always be true due to race conditions, but shouldn't crash)
_ = info.GetCurConcentration()
// Test concurrent coin operations
wg.Add(numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func(amount int32) {
defer wg.Done()
info.AddCoins(amount)
_ = info.GetCoins()
// Try to remove some coins
info.RemoveCoins(amount / 2)
}(int32(100 + i))
}
wg.Wait()
// Test concurrent resistance operations
wg.Add(numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func(value int16) {
defer wg.Done()
info.SetResistance("heat", value)
_ = info.GetResistance("heat")
info.SetResistance("cold", value+1)
_ = info.GetResistance("cold")
}(int16(i))
}
wg.Wait()
}
func TestInfoStructLargeValues(t *testing.T) {
info := NewInfoStruct()
// Test with large coin amounts
largeCoinAmount := int32(2000000000) // 2 billion copper
info.AddCoins(largeCoinAmount)
totalCoins := info.GetCoins()
if totalCoins != largeCoinAmount {
t.Errorf("Expected large coin amount %d, got %d", largeCoinAmount, totalCoins)
}
// Test removing large amounts
success := info.RemoveCoins(largeCoinAmount)
if !success {
t.Error("Expected to be able to remove large coin amount")
}
if info.GetCoins() != 0 {
t.Errorf("Expected coins to be 0 after removing all, got %d", info.GetCoins())
}
// Test with maximum values
info.SetMaxConcentration(32767) // Max int16
info.SetLevel(32767)
if info.GetMaxConcentration() != 32767 {
t.Errorf("Expected max concentration 32767, got %d", info.GetMaxConcentration())
}
if info.GetLevel() != 32767 {
t.Errorf("Expected level 32767, got %d", info.GetLevel())
}
}
func TestInfoStructEdgeCases(t *testing.T) {
info := NewInfoStruct()
// Test negative values
info.SetStr(-5.0)
if info.GetStr() != -5.0 {
t.Errorf("Expected negative strength -5.0, got %f", info.GetStr())
}
// Test zero values
info.SetMaxConcentration(0)
success := info.AddConcentration(1)
if success {
t.Error("Expected AddConcentration to fail with max concentration 0")
}
// Test very small float values
info.SetAgi(0.001)
if info.GetAgi() != 0.001 {
t.Errorf("Expected small agility 0.001, got %f", info.GetAgi())
}
// Test empty string name
info.SetName("")
if info.GetName() != "" {
t.Errorf("Expected empty name, got '%s'", info.GetName())
}
// Test very long name
longName := string(make([]byte, 1000))
for i := range longName {
longName = longName[:i] + "A" + longName[i+1:]
}
info.SetName(longName)
if info.GetName() != longName {
t.Error("Expected to handle very long names")
}
}