Skip to content

Commit 7b6fb53

Browse files
authored
Refactor buy similar to match by stat descriptors and add tests (#2314)
1 parent 16d7e40 commit 7b6fb53

8 files changed

Lines changed: 587 additions & 351 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
describe("Buy similar mod stat matching", function()
2+
local bs = LoadModule("Classes/CompareBuySimilar")
3+
4+
describe("addModEntries mod matching", function()
5+
it("matches from nothing mods as options", function()
6+
local fromNothing = new("Item", [[
7+
From Nothing
8+
Diamond
9+
LevelReq: 0
10+
Radius: Small
11+
Limited to: 1
12+
Implicits: 0
13+
Passives in radius of Zealot's Oath can be Allocated without being connected to your tree
14+
Corrupted]])
15+
16+
local modSources = {
17+
{ list = fromNothing.explicitModLines, type = "explicit" }
18+
}
19+
local modEntries = bs.addModEntries(fromNothing, modSources)
20+
assert.equal(1, #modEntries)
21+
assert.same(
22+
{
23+
formattedLines = { colorCodes.MAGIC.."Passives in radius of Zealot's Oath can be Allocated without being connected to your tree" },
24+
type =
25+
"explicit",
26+
isOption = true,
27+
invert = false,
28+
tradeIds = { "explicit.stat_2422708892|52" },
29+
value = nil
30+
},
31+
modEntries[1])
32+
end)
33+
34+
it("combines mods that are the same stat", function()
35+
local lifeDiamond = new("Item", [[
36+
Test Subject
37+
Diamond
38+
Implicits: 0
39+
+100 to Maximum Life
40+
+50 to Maximum Life
41+
+50% to Fire Resistance]])
42+
43+
local entries = bs.addModEntries(lifeDiamond, { { list = lifeDiamond.explicitModLines, type = "explicit" } })
44+
assert.equal(2, #entries)
45+
assert.equal(2, #entries[1].formattedLines)
46+
assert.equal("+100 to Maximum Life", StripEscapes(entries[1].formattedLines[1]))
47+
assert.equal("+50 to Maximum Life", StripEscapes(entries[1].formattedLines[2]))
48+
assert.equal(150, entries[1].value)
49+
50+
local lifelessDiamond = new("Item", [[
51+
Test Subject
52+
Diamond
53+
Implicits: 0
54+
-100 to Maximum Life
55+
+50 to Maximum Life
56+
+50% to Fire Resistance]])
57+
local entries = bs.addModEntries(lifelessDiamond,
58+
{ { list = lifelessDiamond.explicitModLines, type = "explicit" } })
59+
assert.equal(2, #entries)
60+
assert.equal(2, #entries[1].formattedLines)
61+
assert.equal(-50, entries[1].value)
62+
end)
63+
64+
it("is not case-sensitive", function ()
65+
local funnyItem = new("Item", [[
66+
Test Subject
67+
Diamond
68+
Implicits: 1
69+
+50 tO MaxIMum lifE]])
70+
71+
local entries = bs.addModEntries(funnyItem, {{list = funnyItem.implicitModLines, type = "implicit"}})
72+
assert.equal(1, #entries)
73+
end)
74+
75+
it("does not combine implicit and explicit mods", function()
76+
local lifelessDiamond = new("Item", [[
77+
Test Subject
78+
Diamond
79+
Implicits: 1
80+
-100 to Maximum Life
81+
+50 to Maximum Life]])
82+
local entries = bs.addModEntries(lifelessDiamond,
83+
{ { list = lifelessDiamond.implicitModLines, type = "implicit" }, { list = lifelessDiamond.explicitModLines, type = "explicit" } })
84+
assert.equal(2, #entries)
85+
assert.equal(-100, entries[1].value)
86+
assert.equal(50, entries[2].value)
87+
end)
88+
end)
89+
end)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
describe("TradeHelpers trade hash matching", function()
2+
local tradeHelpers = LoadModule("Classes/TradeHelpers")
3+
4+
---@param ids number[]
5+
---@param expected number
6+
---@return boolean contains whether the given array contains the expected id
7+
local function contains(ids, expected)
8+
for _, id in ipairs(ids) do
9+
if id == expected then return true end
10+
end
11+
return false
12+
end
13+
14+
describe("modLineValue", function()
15+
it("returns the single number on a line", function()
16+
assert.equal(50, tradeHelpers.modLineValue("+50 to maximum Life"))
17+
end)
18+
19+
it("returns the midpoint of a '# to #' range", function()
20+
assert.equal(15, tradeHelpers.modLineValue("Adds 10 to 20 Fire Damage"))
21+
assert.equal(12.5, tradeHelpers.modLineValue("Adds 10 to 15 Fire Damage"))
22+
end)
23+
24+
it("handles negative numbers", function()
25+
assert.equal(-10, tradeHelpers.modLineValue("-10% to Fire Resistance"))
26+
end)
27+
28+
it("returns nil when onlyFromTo is set and there is no range", function()
29+
assert.is_nil(tradeHelpers.modLineValue("+50 to maximum Life", true))
30+
end)
31+
end)
32+
33+
describe("findTradeHash", function()
34+
it("matches a simple mod", function()
35+
local ids, value = tradeHelpers.findTradeHash("+50 to maximum Life")
36+
assert.equal(50, value)
37+
assert.is_true(contains(ids, HashStats({ "base_maximum_life" })))
38+
end)
39+
40+
it("matches a percentage mod", function()
41+
local ids, value = tradeHelpers.findTradeHash("25% reduced maximum Energy Shield")
42+
assert.equal(25, value)
43+
assert.is_true(contains(ids, HashStats({ "maximum_energy_shield_+%" })))
44+
end)
45+
46+
it("matches a # to # mod", function()
47+
local ids, value = tradeHelpers.findTradeHash("Adds 5 to 15 Fire Damage")
48+
assert.equal(10, value)
49+
assert.is_true(contains(ids,
50+
HashStats({ "local_minimum_added_fire_damage", "local_maximum_added_fire_damage" })))
51+
end)
52+
53+
it("is case-insensitive", function()
54+
local ids = tradeHelpers.findTradeHash(
55+
"Each ArroW fIred is a Crescendo, Splinter, Reversing, Diamond, Covetous, or Blunt Arrow")
56+
assert.is_true(contains(ids, HashStats({ "each_arrow_fired_gains_random_perdandus_prefix" })))
57+
end)
58+
59+
it("returns no results for an unmatchable line", function()
60+
local ids = tradeHelpers.findTradeHash("+100 to IQ")
61+
assert.equal(0, #ids)
62+
end)
63+
64+
it("works thrice in a row", function()
65+
local a = tradeHelpers.findTradeHash("+50 to maximum Life")
66+
local b = tradeHelpers.findTradeHash("+50 to maximum Life")
67+
local c = tradeHelpers.findTradeHash("+50 to maximum Life")
68+
assert.same(a, b)
69+
assert.same(b, c)
70+
end)
71+
72+
it("detects inverted mods correctly", function()
73+
-- note that this stat is a handwrap mod and doesn't actually exist on the trade site
74+
local ids, value, shouldNegate = tradeHelpers.findTradeHash("100% more damage taken while on low life")
75+
assert.equal(100, value)
76+
assert.is_true(shouldNegate)
77+
assert.equal(1, #ids)
78+
79+
local ids, value, shouldNegate = tradeHelpers.findTradeHash("67% reduced maximum life")
80+
assert.equal(67, value)
81+
assert.is_true(shouldNegate)
82+
assert.equal(1, #ids)
83+
end)
84+
it("detects mods with lua pattern characters correctly", function()
85+
-- there is a form of this line which is literally 3.5% without a variable
86+
local ids, value = tradeHelpers.findTradeHash("Socketed Gems have +3.5% Critical Hit Chance")
87+
assert.is_true(contains(ids, HashStats({ "local_display_socketed_gems_additional_critical_strike_chance_%" })))
88+
-- for some reason the range is 3-3 on the descriptor. this behaviour is still correct
89+
assert.equal(3, value)
90+
91+
local ids, value, shouldNegate = tradeHelpers.findTradeHash(
92+
"10% reduced effect of Non-Curse Auras from your Skills on your Minions")
93+
assert.is_true(contains(ids, HashStats({ "minions_have_non_curse_aura_effect_+%_from_parent_skills" })))
94+
assert.equal(10, value)
95+
assert.is_true(shouldNegate)
96+
end)
97+
98+
it("matches time-lost jewel mods correctly", function()
99+
local ids, value = tradeHelpers.findTradeHash(
100+
"Small Passive Skills in Radius also grant 3% increased Damage with Bows")
101+
assert.equal(1, #ids)
102+
assert.is_true(contains(ids, HashStats({ "bow_damage_+%", "local_jewel_mod_stats_added_to_small_passives" })))
103+
assert.equal(3, value)
104+
105+
local ids, value = tradeHelpers.findTradeHash(
106+
"Notable Passive Skills in Radius also grant 7% increased Critical Hit Chance for Attacks")
107+
assert.is_true(contains(ids,
108+
HashStats({ "attack_critical_strike_chance_+%", "local_jewel_mod_stats_added_to_notable_passives" })))
109+
assert.equal(7, value)
110+
end)
111+
end)
112+
end)

0 commit comments

Comments
 (0)