Files
wow-item-generator/internal/items/item_test.go

451 lines
10 KiB
Go

package items
import (
"io"
"log"
"math"
"reflect"
"testing"
"golang.org/x/exp/rand"
)
func TestGetPrimaryStat(t *testing.T) {
originalLog := log.Writer()
log.SetOutput(io.Discard)
defer log.SetOutput(originalLog)
tests := []struct {
name string
item Item
wantStat int
wantValue int
expectError bool
}{
{
name: "No primary stat found",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(1), StatValue1: ptrInt(10),
StatType2: ptrInt(2), StatValue2: ptrInt(20),
StatType3: ptrInt(12), StatValue3: ptrInt(15),
},
wantStat: 0,
wantValue: 0,
expectError: false,
},
{
name: "Primary stat found with higher value",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
wantStat: 4, // Strength
wantValue: 20,
expectError: false,
},
{
name: "Primary stat found with lower value",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(30), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
wantStat: 3, // Agility
wantValue: 30,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotStat, gotValue, err := tt.item.GetPrimaryStat()
if (err != nil) != tt.expectError {
t.Errorf("GetPrimaryStat() error = %v, expectError %v", err, tt.expectError)
return
}
if gotStat != tt.wantStat {
t.Errorf("GetPrimaryStat() gotStat = %v, want %v", gotStat, tt.wantStat)
}
if gotValue != tt.wantValue {
t.Errorf("GetPrimaryStat() gotValue = %v, want %v", gotValue, tt.wantValue)
}
})
}
}
func TestGetStatList(t *testing.T) {
originalLog := log.Writer()
log.SetOutput(io.Discard)
defer log.SetOutput(originalLog)
tests := []struct {
name string
item Item
want []int
expectError bool
}{
{
name: "No stats available",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(0), StatValue1: ptrInt(0),
StatType2: ptrInt(0), StatValue2: ptrInt(0),
},
want: []int{},
expectError: false,
},
{
name: "Multiple stats available",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
},
want: []int{3, 4, 5},
expectError: false,
},
{
name: "Stats are ordered correctly",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(7), StatValue1: ptrInt(10), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(31), StatValue3: ptrInt(15), // Intellect
},
want: []int{4, 7, 31},
expectError: false,
},
{
name: "Some stats are zero",
item: Item{
Entry: 1,
Name: "Test Item",
StatType1: ptrInt(3), StatValue1: ptrInt(0), // Agility
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
StatType3: ptrInt(5), StatValue3: ptrInt(0), // Intellect
},
want: []int{4},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.item.GetStatList()
if (err != nil) != tt.expectError {
t.Errorf("GetStatList() error = %v, expectError %v", err, tt.expectError)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetStatList() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetDPS(t *testing.T) {
tests := []struct {
name string
item Item
wantDPS float64
expectError bool
}{
{
name: "Valid DPS calculation",
item: Item{
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Delay: ptrFloat64(3000),
},
wantDPS: 20.00,
expectError: false,
},
{
name: "High damage DPS calculation",
item: Item{
MinDmg1: ptrInt(100),
MaxDmg1: ptrInt(150),
Delay: ptrFloat64(2000),
},
wantDPS: 62.50,
expectError: false,
},
{
name: "Low damage DPS calculation",
item: Item{
MinDmg1: ptrInt(10),
MaxDmg1: ptrInt(15),
Delay: ptrFloat64(1500),
},
wantDPS: 8.33,
expectError: false,
},
{
name: "Missing MinDmg1",
item: Item{
MaxDmg1: ptrInt(70),
Delay: ptrFloat64(3000),
},
wantDPS: 0,
expectError: true,
},
{
name: "Missing MaxDmg1",
item: Item{
MinDmg1: ptrInt(50),
Delay: ptrFloat64(3000),
},
wantDPS: 0,
expectError: true,
},
{
name: "Missing Delay",
item: Item{
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
},
wantDPS: 0,
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotDPS, err := tt.item.GetDPS()
if (err != nil) != tt.expectError {
t.Errorf("GetDPS() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && !almostEqual(gotDPS, tt.wantDPS, 0.01) {
t.Errorf("GetDPS() = %v, want %v", gotDPS, tt.wantDPS)
}
})
}
}
func TestScaleDPS(t *testing.T) {
tests := []struct {
name string
item Item
level int
wantDPSMin float64
wantDPSMax float64
expectError bool
}{
{
name: "Valid Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(60),
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 53.0, // Expected DPS range due to randomness
wantDPSMax: 107.0,
expectError: false,
},
{
name: "High level Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(80),
Delay: ptrFloat64(2000),
MinDmg1: ptrInt(150),
MaxDmg1: ptrInt(200),
Subclass: ptrInt(17), // Two-handed weapon
Quality: ptrInt(4), // Epic
},
level: 100,
wantDPSMin: 120.0, // Expected DPS range due to randomness
wantDPSMax: 240.0,
expectError: false,
},
{
name: "Low level Scale DPS calculation",
item: Item{
ItemLevel: ptrInt(20),
Delay: ptrFloat64(1000),
MinDmg1: ptrInt(30),
MaxDmg1: ptrInt(50),
Subclass: ptrInt(2), // Ranged weapon
Quality: ptrInt(2), // Uncommon
},
level: 25,
wantDPSMin: 21.0, // Expected DPS range due to randomness
wantDPSMax: 42.0,
expectError: false,
},
{
name: "Missing ItemLevel",
item: Item{
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 0,
wantDPSMax: 0,
expectError: true,
},
{
name: "Missing Delay",
item: Item{
ItemLevel: ptrInt(60),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 0,
wantDPSMax: 0,
expectError: true,
},
{
name: "Secondary damage scaling",
item: Item{
ItemLevel: ptrInt(60),
Delay: ptrFloat64(3000),
MinDmg1: ptrInt(50),
MaxDmg1: ptrInt(70),
MinDmg2: ptrInt(25),
MaxDmg2: ptrInt(35),
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
level: 70,
wantDPSMin: 53.0, // Expected DPS range due to randomness
wantDPSMax: 107.0,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Seed the random number generator for consistent test results
rand.Seed(1)
gotDPS, err := tt.item.ScaleDPS(tt.level)
if (err != nil) != tt.expectError {
t.Errorf("ScaleDPS() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && (gotDPS < tt.wantDPSMin || gotDPS > tt.wantDPSMax) {
t.Errorf("ScaleDPS() = %v, want between %v and %v", gotDPS, tt.wantDPSMin, tt.wantDPSMax)
}
})
}
}
func TestGetDpsModifier(t *testing.T) {
tests := []struct {
name string
item Item
wantModifier float64
expectError bool
}{
{
name: "Valid one-handed weapon modifier",
item: Item{
Subclass: ptrInt(4), // One-handed weapon
Quality: ptrInt(3), // Rare
},
wantModifier: 0.64 * 1.38,
expectError: false,
},
{
name: "Valid two-handed weapon modifier",
item: Item{
Subclass: ptrInt(17), // Two-handed weapon
Quality: ptrInt(4), // Epic
},
wantModifier: 0.80 * 1.5,
expectError: false,
},
{
name: "Valid ranged weapon modifier",
item: Item{
Subclass: ptrInt(2), // Ranged weapon
Quality: ptrInt(2), // Uncommon
},
wantModifier: 0.70 * 1.25,
expectError: false,
},
{
name: "Valid wand modifier",
item: Item{
Subclass: ptrInt(19), // Wand
Quality: ptrInt(4), // Epic
},
wantModifier: 0.70 * 1.5,
expectError: false,
},
{
name: "Invalid subclass",
item: Item{
Subclass: ptrInt(99), // Invalid subclass
Quality: ptrInt(3), // Rare
},
wantModifier: 0,
expectError: true,
},
{
name: "Missing subclass",
item: Item{
Quality: ptrInt(3), // Rare
},
wantModifier: 0,
expectError: true,
},
{
name: "Missing quality",
item: Item{
Subclass: ptrInt(4), // One-handed weapon
},
wantModifier: 0,
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotModifier, err := tt.item.GetDpsModifier()
if (err != nil) != tt.expectError {
t.Errorf("GetDpsModifier() error = %v, expectError %v", err, tt.expectError)
return
}
if !tt.expectError && !almostEqual(gotModifier, tt.wantModifier, 0.01) {
t.Errorf("GetDpsModifier() = %v, want %v", gotModifier, tt.wantModifier)
}
})
}
}
// Helper function to return a pointer to an int
func ptrInt(i int) *int {
return &i
}
func ptrFloat64(f float64) *float64 {
return &f
}
func almostEqual(a, b, tolerance float64) bool {
return math.Abs(a-b) <= tolerance
}