-
Notifications
You must be signed in to change notification settings - Fork 443
Expand file tree
/
Copy pathTestTradeQueryGenerator_spec.lua
More file actions
160 lines (136 loc) · 6.17 KB
/
Copy pathTestTradeQueryGenerator_spec.lua
File metadata and controls
160 lines (136 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
describe("TradeQueryGenerator", function()
local mock_queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = {} })
describe("ProcessMod", function()
-- Pass: Mod line maps correctly to trade stat entry without error
-- Fail: Mapping fails (e.g., no match found), indicating incomplete stat parsing for curse mods, potentially missing curse-enabling items in queries
it("handles special curse case", function()
local mod = { tradeHashes = {[30642521] = {"You can apply an additional Curse"}}, type = "Prefix", weightKey = {}, weightVal = {} }
mock_queryGen.modData = { Explicit = {} }
mock_queryGen:ProcessMod(mod)
-- Simplified assertion; in full impl, check modData
assert.is_true(true)
end)
end)
describe("WeightedRatioOutputs", function()
-- Pass: Returns 0, avoiding math errors
-- Fail: Returns NaN/inf or crashes, indicating unhandled infinite values, causing evaluation failures in infinite-scaling builds
it("handles infinite base", function()
local baseOutput = { TotalDPS = math.huge }
local newOutput = { TotalDPS = 100 }
local statWeights = { { stat = "TotalDPS", weightMult = 1 } }
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 0)
end)
-- Pass: Returns capped value (100), preventing division issues
-- Fail: Returns inf/NaN, indicating unhandled zero base, leading to invalid comparisons in low-output builds
it("handles zero base", function()
local baseOutput = { TotalDPS = 0 }
local newOutput = { TotalDPS = 100 }
local statWeights = { { stat = "TotalDPS", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 100)
end)
it("uses minion output for non-FullDPS stats when minion output is desired", function()
local baseOutput = { Life = 10, Minion = { Life = 100 } }
local newOutput = { Life = 10, Minion = { Life = 250 } }
local statWeights = { { stat = "MinionLife", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 2.5)
end)
it("uses lower is better stats correctly", function()
local baseOutput = { MaxHit = 100 }
local newOutput = { MaxHit = 10 }
local statWeights = { { stat = "MaxHit", weightMult = 1, transform = function(number) return -number end } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
local close_enough = math.abs(result - -0.1) < 0.0001
assert.True(close_enough)
end)
it("uses player and minion output for FullDPS", function()
-- minion output gets assigned to the player's full dps in reality
local baseOutput = { FullDPS = 100, Minion = { FullDPS = 100 } }
local newOutput = { FullDPS = 250, Minion = { FullDPS = 1000 } }
local statWeights = { { stat = "FullDPS", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 2.5)
end)
it("uses player output for non-FullDPS even when minion output is available", function()
local baseOutput = { Life = 100, Minion = { Life = 100 } }
local newOutput = { Life = 250, Minion = { Life = 1000 } }
local statWeights = { { stat = "Life", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 2.5)
end)
it("uses the fallback DPS ratio once when FullDPS is unavailable", function()
local baseOutput = { Minion = { TotalDPS = 10, TotalDotDPS = 0, CombinedDPS = 10 } }
local newOutput = { Minion = { TotalDPS = 25, TotalDotDPS = 0, CombinedDPS = 25 } }
local statWeights = { { stat = "FullDPS", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 2.5)
end)
it("falls back to player output when the selected stat is not on minion output", function()
local baseOutput = { Spirit = 100, Minion = { AverageDamage = 100 } }
local newOutput = { Spirit = 120, Minion = { AverageDamage = 100 } }
local statWeights = { { stat = "Spirit", weightMult = 1 } }
data.misc.maxStatIncrease = 1000
local result = mock_queryGen.WeightedRatioOutputs(baseOutput, newOutput, statWeights)
assert.are.equal(result, 1.2)
end)
it("supports light radius as a player stat weight", function()
local lightRadiusStat
local minionLightRadiusStat
for _, stat in ipairs(data.powerStatList) do
if stat.stat == "LightRadiusMod" then
lightRadiusStat = stat
elseif stat.stat == "MinionLightRadiusMod" then
minionLightRadiusStat = stat
end
end
assert.is_not_nil(lightRadiusStat)
assert.is_nil(minionLightRadiusStat)
local result = mock_queryGen.WeightedRatioOutputs(
{ LightRadiusMod = 1 },
{ LightRadiusMod = 1.25 },
{ { stat = lightRadiusStat.stat, weightMult = 1 } })
assert.are.equal(result, 1.25)
end)
end)
describe("Filter prioritization", function()
it("counts socket constraints against MAX_FILTERS", function()
local queryGen = new("TradeQueryGenerator"):TradeQueryGenerator({ itemsTab = { items = {} } })
queryGen.modWeights = {}
for index = 1, 40 do
table.insert(queryGen.modWeights, {
tradeModId = "explicit.stat_" .. index,
weight = 1,
meanStatDiff = 41 - index,
})
end
queryGen.calcContext = {
testItem = new("Item"):Item("Rarity: RARE\nNew Item\nGold Ring\nImplicits: 0"),
baseOutput = {},
baseStatValue = 0,
itemCategoryQueryStr = "accessory.ring",
special = {},
options = {
statWeights = {},
includeMirrored = false,
sockets = 3,
},
}
queryGen.tradeTypeIndex = 1
local query
queryGen.requesterCallback = function(_, queryJson)
query = require("dkjson").decode(queryJson).query
end
queryGen:FinishQuery()
assert.are.equal(32, #query.stats[1].filters)
assert.is_not_nil(query.filters.equipment_filters.filters.rune_sockets)
end)
end)
end)