AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
SpellProcPPMTest.cpp File Reference

Unit tests for PPM (Procs Per Minute) calculation. More...

#include "ProcChanceTestHelper.h"
#include "UnitStub.h"
#include "gtest/gtest.h"

Go to the source code of this file.

Classes

class  SpellProcPPMTest
 

Functions

 TEST_F (SpellProcPPMTest, PPMFormula_BasicCalculation)
 
 TEST_F (SpellProcPPMTest, PPMFormula_FastWeapon_HigherChancePerSwing)
 
 TEST_F (SpellProcPPMTest, PPMFormula_SlowWeapon_LowerChancePerSwing)
 
 TEST_F (SpellProcPPMTest, PPMFormula_VerySlowWeapon)
 
 TEST_F (SpellProcPPMTest, PPMFormula_ZeroPPM_ReturnsZero)
 
 TEST_F (SpellProcPPMTest, PPMFormula_NegativePPM_ReturnsZero)
 
 TEST_F (SpellProcPPMTest, PPMFormula_WithPositiveModifier)
 
 TEST_F (SpellProcPPMTest, PPMFormula_WithNegativeModifier)
 
 TEST_F (SpellProcPPMTest, UnitStub_GetPPMProcChance_DefaultWeaponSpeed)
 
 TEST_F (SpellProcPPMTest, UnitStub_GetPPMProcChance_CustomWeaponSpeed)
 
 TEST_F (SpellProcPPMTest, UnitStub_GetPPMProcChance_WithPPMModifier)
 
 TEST_F (SpellProcPPMTest, UnitStub_GetPPMProcChance_ModifierNotAppliedWithoutSpellId)
 
 TEST_F (SpellProcPPMTest, OmenOfClarity_PPM6_VariousWeaponSpeeds)
 
 TEST_F (SpellProcPPMTest, JudgementOfLight_PPM15_VariousWeaponSpeeds)
 
 TEST_F (SpellProcPPMTest, WindfuryWeapon_PPM2_VariousWeaponSpeeds)
 
 TEST_F (SpellProcPPMTest, EdgeCase_VeryFastWeapon)
 
 TEST_F (SpellProcPPMTest, EdgeCase_ExtremelySlow)
 
 TEST_F (SpellProcPPMTest, EdgeCase_HighPPM)
 
 TEST_F (SpellProcPPMTest, EdgeCase_FractionalPPM)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_NonShifted_NoDiscrepancy)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_CatForm_ProtoDelayInflatesChance)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_CatForm_EffectivePPMIs3Point6x)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_BearForm_ProtoDelayInflatesChance)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_CatForm_FieryWeapon6PPM)
 
 TEST_F (SpellProcPPMTest, ShapeshiftBug_ItemSpellPath_AlreadyCorrect)
 

Detailed Description

Unit tests for PPM (Procs Per Minute) calculation.

Tests the formula: chance = (WeaponSpeed * PPM) / 600.0f

Definition in file SpellProcPPMTest.cpp.

Function Documentation

◆ TEST_F() [1/25]

TEST_F ( SpellProcPPMTest  ,
EdgeCase_ExtremelySlow   
)
206{
207 // Extremely slow weapon - 5.0 sec = 5000ms
208 float result = ProcChanceTestHelper::CalculatePPMChance(5000, 6.0f);
209 EXPECT_NEAR(result, 50.0f, 0.01f);
210}
static float CalculatePPMChance(uint32 weaponSpeed, float ppm, float ppmModifier=0.0f)
Calculate PPM proc chance Implements the formula: (WeaponSpeed * PPM) / 600.0f.
Definition ProcChanceTestHelper.h:46

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [2/25]

TEST_F ( SpellProcPPMTest  ,
EdgeCase_FractionalPPM   
)
221{
222 // Fractional PPM value (2.5)
223 float result = ProcChanceTestHelper::CalculatePPMChance(2400, 2.5f);
224 // 2400 * 2.5 / 600 = 10%
225 EXPECT_NEAR(result, 10.0f, 0.01f);
226}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [3/25]

TEST_F ( SpellProcPPMTest  ,
EdgeCase_HighPPM   
)
213{
214 // High PPM value (30)
215 float result = ProcChanceTestHelper::CalculatePPMChance(2500, 30.0f);
216 // 2500 * 30 / 600 = 125% (can exceed 100%)
217 EXPECT_NEAR(result, 125.0f, 0.01f);
218}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [4/25]

TEST_F ( SpellProcPPMTest  ,
EdgeCase_VeryFastWeapon   
)
199{
200 // Very fast (theoretical) weapon - 1.0 sec = 1000ms
201 float result = ProcChanceTestHelper::CalculatePPMChance(1000, 6.0f);
202 EXPECT_NEAR(result, 10.0f, 0.01f);
203}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [5/25]

TEST_F ( SpellProcPPMTest  ,
JudgementOfLight_PPM15_VariousWeaponSpeeds   
)
163{
164 // Judgement of Light: 15 PPM
165 constexpr float JOL_PPM = 15.0f;
166
167 // Fast dagger
168 float daggerChance = ProcChanceTestHelper::CalculatePPMChance(1400, JOL_PPM);
169 EXPECT_NEAR(daggerChance, 35.0f, 0.01f);
170
171 // Normal 1H sword
172 float swordChance = ProcChanceTestHelper::CalculatePPMChance(2500, JOL_PPM);
173 EXPECT_NEAR(swordChance, 62.5f, 0.01f);
174
175 // Slow 2H weapon
176 float twoHanderChance = ProcChanceTestHelper::CalculatePPMChance(3300, JOL_PPM);
177 EXPECT_NEAR(twoHanderChance, 82.5f, 0.01f);
178}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [6/25]

TEST_F ( SpellProcPPMTest  ,
OmenOfClarity_PPM6_VariousWeaponSpeeds   
)
145{
146 // Omen of Clarity: 6 PPM
147 constexpr float OOC_PPM = 6.0f;
148
149 // Fast dagger
150 float daggerChance = ProcChanceTestHelper::CalculatePPMChance(1400, OOC_PPM);
151 EXPECT_NEAR(daggerChance, 14.0f, 0.01f);
152
153 // Normal 1H sword
154 float swordChance = ProcChanceTestHelper::CalculatePPMChance(2500, OOC_PPM);
155 EXPECT_NEAR(swordChance, 25.0f, 0.01f);
156
157 // Staff
158 float staffChance = ProcChanceTestHelper::CalculatePPMChance(3000, OOC_PPM);
159 EXPECT_NEAR(staffChance, 30.0f, 0.01f);
160}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [7/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_BasicCalculation   
)
47{
48 // Formula: (WeaponSpeed * PPM) / 600.0f
49 // 2500ms * 6 PPM / 600 = 25%
50 float result = ProcChanceTestHelper::CalculatePPMChance(2500, 6.0f);
51 EXPECT_NEAR(result, 25.0f, 0.01f);
52}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [8/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_FastWeapon_HigherChancePerSwing   
)
55{
56 // Fast dagger (1.4 sec = 1400ms), 6 PPM
57 // 1400 * 6 / 600 = 14%
58 float result = ProcChanceTestHelper::CalculatePPMChance(1400, 6.0f);
59 EXPECT_NEAR(result, 14.0f, 0.01f);
60}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [9/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_NegativePPM_ReturnsZero   
)
85{
86 float result = ProcChanceTestHelper::CalculatePPMChance(2500, -1.0f);
87 EXPECT_FLOAT_EQ(result, 0.0f);
88}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [10/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_SlowWeapon_LowerChancePerSwing   
)
63{
64 // Slow 2H (3.3 sec = 3300ms), 6 PPM
65 // 3300 * 6 / 600 = 33%
66 float result = ProcChanceTestHelper::CalculatePPMChance(3300, 6.0f);
67 EXPECT_NEAR(result, 33.0f, 0.01f);
68}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [11/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_VerySlowWeapon   
)
71{
72 // Very slow weapon (3.8 sec = 3800ms), 6 PPM
73 // 3800 * 6 / 600 = 38%
74 float result = ProcChanceTestHelper::CalculatePPMChance(3800, 6.0f);
75 EXPECT_NEAR(result, 38.0f, 0.01f);
76}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [12/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_WithNegativeModifier   
)
99{
100 // 2500ms, 6 PPM - 2 PPM modifier = 4 effective PPM
101 // 2500 * 4 / 600 = 16.67%
102 float result = ProcChanceTestHelper::CalculatePPMChance(2500, 6.0f, -2.0f);
103 EXPECT_NEAR(result, 16.67f, 0.01f);
104}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [13/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_WithPositiveModifier   
)
91{
92 // 2500ms, 6 PPM + 2 PPM modifier = 8 effective PPM
93 // 2500 * 8 / 600 = 33.33%
94 float result = ProcChanceTestHelper::CalculatePPMChance(2500, 6.0f, 2.0f);
95 EXPECT_NEAR(result, 33.33f, 0.01f);
96}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [14/25]

TEST_F ( SpellProcPPMTest  ,
PPMFormula_ZeroPPM_ReturnsZero   
)
79{
80 float result = ProcChanceTestHelper::CalculatePPMChance(2500, 0.0f);
81 EXPECT_FLOAT_EQ(result, 0.0f);
82}

References ProcChanceTestHelper::CalculatePPMChance().

◆ TEST_F() [15/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_BearForm_ProtoDelayInflatesChance   
)
304{
305 // Bear Form with 3.6s staff: proto->Delay = 3600, GetAttackTime = 2500
306 constexpr uint32 STAFF_DELAY = ProcChanceTestHelper::WEAPON_SPEED_STAFF;
307 constexpr uint32 BEAR_SPEED = ProcChanceTestHelper::FORM_SPEED_BEAR;
308 constexpr float MONGOOSE_PPM = 1.0f;
309
310 _unit->SetAttackTime(0, BEAR_SPEED);
311
312 float buggyChance = ProcChanceTestHelper::CalculatePPMChance(STAFF_DELAY, MONGOOSE_PPM);
313 float correctChance = ProcChanceTestHelper::CalculatePPMChance(BEAR_SPEED, MONGOOSE_PPM);
314
315 float buggyEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(buggyChance, BEAR_SPEED);
316 float correctEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(correctChance, BEAR_SPEED);
317
318 // Buggy: 1.44 PPM instead of 1.0
319 EXPECT_NEAR(buggyEffectivePPM, 1.44f, 0.01f)
320 << "Bug: Bear Form Mongoose procs 1.44 times/min instead of 1.0";
321 EXPECT_NEAR(correctEffectivePPM, MONGOOSE_PPM, 0.01f)
322 << "Fix: Bear Form Mongoose should proc exactly 1.0 times/min";
323}
std::uint32_t uint32
Definition Define.h:107
static constexpr uint32 FORM_SPEED_BEAR
Definition ProcChanceTestHelper.h:196
static float CalculateEffectivePPM(float chancePerSwing, uint32 actualSwingSpeedMs)
Simulate effective procs per minute.
Definition ProcChanceTestHelper.h:208
static constexpr uint32 WEAPON_SPEED_STAFF
Definition ProcChanceTestHelper.h:190

References ProcChanceTestHelper::CalculateEffectivePPM(), ProcChanceTestHelper::CalculatePPMChance(), ProcChanceTestHelper::FORM_SPEED_BEAR, and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [16/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_CatForm_EffectivePPMIs3Point6x   
)
281{
282 // Cat Form attacks every 1.0s (60 swings/min)
283 // With the buggy 6.0% chance per swing: 60 * 0.06 = 3.6 procs/min
284 // With the correct 1.67% chance: 60 * 0.0167 = 1.0 procs/min
285 constexpr uint32 STAFF_DELAY = ProcChanceTestHelper::WEAPON_SPEED_STAFF;
286 constexpr uint32 CAT_SPEED = ProcChanceTestHelper::FORM_SPEED_CAT;
287 constexpr float MONGOOSE_PPM = 1.0f;
288
289 float buggyChance = ProcChanceTestHelper::CalculatePPMChance(STAFF_DELAY, MONGOOSE_PPM);
290 float correctChance = ProcChanceTestHelper::CalculatePPMChance(CAT_SPEED, MONGOOSE_PPM);
291
292 float buggyEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(buggyChance, CAT_SPEED);
293 float correctEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(correctChance, CAT_SPEED);
294
295 // Buggy: effective PPM is 3.6 instead of 1.0
296 EXPECT_NEAR(buggyEffectivePPM, 3.6f, 0.01f)
297 << "Bug: Cat Form Mongoose procs 3.6 times/min instead of 1.0";
298 // Correct: effective PPM matches the intended value
299 EXPECT_NEAR(correctEffectivePPM, MONGOOSE_PPM, 0.01f)
300 << "Fix: Cat Form Mongoose should proc exactly 1.0 times/min";
301}
static constexpr uint32 FORM_SPEED_CAT
Shapeshift form base attack speeds (from SpellShapeshiftForm.dbc)
Definition ProcChanceTestHelper.h:195

References ProcChanceTestHelper::CalculateEffectivePPM(), ProcChanceTestHelper::CalculatePPMChance(), ProcChanceTestHelper::FORM_SPEED_CAT, and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [17/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_CatForm_FieryWeapon6PPM   
)
326{
327 // Fiery Weapon (6 PPM) in Cat Form with 3.6s staff
328 constexpr uint32 STAFF_DELAY = ProcChanceTestHelper::WEAPON_SPEED_STAFF;
329 constexpr uint32 CAT_SPEED = ProcChanceTestHelper::FORM_SPEED_CAT;
330 constexpr float FIERY_PPM = 6.0f;
331
332 float buggyChance = ProcChanceTestHelper::CalculatePPMChance(STAFF_DELAY, FIERY_PPM);
333 float correctChance = ProcChanceTestHelper::CalculatePPMChance(CAT_SPEED, FIERY_PPM);
334
335 float buggyEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(buggyChance, CAT_SPEED);
336 float correctEffectivePPM = ProcChanceTestHelper::CalculateEffectivePPM(correctChance, CAT_SPEED);
337
338 // Buggy: 36% chance per swing → 21.6 procs/min instead of 6.0
339 EXPECT_NEAR(buggyChance, 36.0f, 0.01f);
340 EXPECT_NEAR(correctChance, 10.0f, 0.01f);
341 EXPECT_NEAR(buggyEffectivePPM, 21.6f, 0.01f)
342 << "Bug: Cat Form Fiery Weapon procs 21.6 times/min instead of 6.0";
343 EXPECT_NEAR(correctEffectivePPM, FIERY_PPM, 0.01f)
344 << "Fix: Cat Form Fiery Weapon should proc exactly 6.0 times/min";
345}

References ProcChanceTestHelper::CalculateEffectivePPM(), ProcChanceTestHelper::CalculatePPMChance(), ProcChanceTestHelper::FORM_SPEED_CAT, and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [18/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_CatForm_ProtoDelayInflatesChance   
)
257{
258 // Druid in Cat Form with a 3.6s staff equipped
259 // proto->Delay = 3600ms (the staff), GetAttackTime = 1000ms (Cat Form)
260 constexpr uint32 STAFF_DELAY = ProcChanceTestHelper::WEAPON_SPEED_STAFF;
261 constexpr uint32 CAT_SPEED = ProcChanceTestHelper::FORM_SPEED_CAT;
262 constexpr float MONGOOSE_PPM = 1.0f;
263
264 _unit->SetAttackTime(0, CAT_SPEED);
265
266 float buggyChance = ProcChanceTestHelper::CalculatePPMChance(STAFF_DELAY, MONGOOSE_PPM);
267 float correctChance = ProcChanceTestHelper::CalculatePPMChance(CAT_SPEED, MONGOOSE_PPM);
268
269 // proto->Delay gives 3600 * 1 / 600 = 6.0% per swing
270 EXPECT_NEAR(buggyChance, 6.0f, 0.01f);
271 // GetAttackTime gives 1000 * 1 / 600 = 1.67% per swing
272 EXPECT_NEAR(correctChance, 1.67f, 0.01f);
273
274 // The bug inflates chance per swing by weapon_speed / form_speed
275 EXPECT_NEAR(buggyChance / correctChance,
276 static_cast<float>(STAFF_DELAY) / static_cast<float>(CAT_SPEED), 0.01f)
277 << "Bug inflates per-swing chance by ratio of weapon speed to form speed";
278}

References ProcChanceTestHelper::CalculatePPMChance(), ProcChanceTestHelper::FORM_SPEED_CAT, and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [19/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_ItemSpellPath_AlreadyCorrect   
)
348{
349 // The item spell PPM path (line ~7308) already uses GetAttackTime.
350 // Verify that using GetAttackTime gives correct PPM for all forms.
351 constexpr float PPM = 1.0f;
352
353 struct FormScenario
354 {
355 const char* name;
356 uint32 formSpeed;
357 };
358
359 FormScenario scenarios[] = {
360 {"Normal (3.6s weapon)", ProcChanceTestHelper::WEAPON_SPEED_STAFF},
363 };
364
365 for (auto const& scenario : scenarios)
366 {
367 _unit->SetAttackTime(0, scenario.formSpeed);
368
370 _unit->GetAttackTime(0), PPM);
372 chance, scenario.formSpeed);
373
374 EXPECT_NEAR(effectivePPM, PPM, 0.01f)
375 << scenario.name << ": GetAttackTime-based PPM should always match intended PPM";
376 }
377}

References ProcChanceTestHelper::CalculateEffectivePPM(), ProcChanceTestHelper::CalculatePPMChance(), ProcChanceTestHelper::FORM_SPEED_BEAR, ProcChanceTestHelper::FORM_SPEED_CAT, and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [20/25]

TEST_F ( SpellProcPPMTest  ,
ShapeshiftBug_NonShifted_NoDiscrepancy   
)
241{
242 // A warrior with a 3.6s weapon: proto->Delay == GetAttackTime()
243 constexpr uint32 WEAPON_DELAY = ProcChanceTestHelper::WEAPON_SPEED_STAFF;
244 constexpr float MONGOOSE_PPM = 1.0f;
245
246 _unit->SetAttackTime(0, WEAPON_DELAY);
247
248 float chanceFromProtoDelay = ProcChanceTestHelper::CalculatePPMChance(WEAPON_DELAY, MONGOOSE_PPM);
249 float chanceFromGetAttackTime = ProcChanceTestHelper::CalculatePPMChance(
250 _unit->GetAttackTime(0), MONGOOSE_PPM);
251
252 EXPECT_FLOAT_EQ(chanceFromProtoDelay, chanceFromGetAttackTime)
253 << "Non-shapeshifted: proto->Delay and GetAttackTime() should be identical";
254}

References ProcChanceTestHelper::CalculatePPMChance(), and ProcChanceTestHelper::WEAPON_SPEED_STAFF.

◆ TEST_F() [21/25]

TEST_F ( SpellProcPPMTest  ,
UnitStub_GetPPMProcChance_CustomWeaponSpeed   
)
118{
119 _unit->SetAttackTime(0, 2500); // BASE_ATTACK
120 float result = _unit->GetPPMProcChance(_unit->GetAttackTime(0), 6.0f);
121 EXPECT_NEAR(result, 25.0f, 0.01f);
122}

◆ TEST_F() [22/25]

TEST_F ( SpellProcPPMTest  ,
UnitStub_GetPPMProcChance_DefaultWeaponSpeed   
)
111{
112 // Default weapon speed is 2000ms
113 float result = _unit->GetPPMProcChance(2000, 6.0f);
114 EXPECT_NEAR(result, 20.0f, 0.01f);
115}

◆ TEST_F() [23/25]

TEST_F ( SpellProcPPMTest  ,
UnitStub_GetPPMProcChance_ModifierNotAppliedWithoutSpellId   
)
133{
134 _unit->SetPPMModifier(12345, 2.0f);
135 // Without spell ID, modifier is not applied
136 float result = _unit->GetPPMProcChance(2500, 6.0f, 0);
137 EXPECT_NEAR(result, 25.0f, 0.01f);
138}

◆ TEST_F() [24/25]

TEST_F ( SpellProcPPMTest  ,
UnitStub_GetPPMProcChance_WithPPMModifier   
)
125{
126 _unit->SetPPMModifier(12345, 2.0f); // Spell ID 12345 has +2 PPM modifier
127 float result = _unit->GetPPMProcChance(2500, 6.0f, 12345);
128 // 2500 * (6 + 2) / 600 = 33.33%
129 EXPECT_NEAR(result, 33.33f, 0.01f);
130}

◆ TEST_F() [25/25]

TEST_F ( SpellProcPPMTest  ,
WindfuryWeapon_PPM2_VariousWeaponSpeeds   
)
181{
182 // Windfury Weapon: 2 PPM (low PPM for testing)
183 constexpr float WF_PPM = 2.0f;
184
185 // Fast dagger
186 float daggerChance = ProcChanceTestHelper::CalculatePPMChance(1400, WF_PPM);
187 EXPECT_NEAR(daggerChance, 4.67f, 0.01f);
188
189 // Slow 2H weapon
190 float twoHanderChance = ProcChanceTestHelper::CalculatePPMChance(3300, WF_PPM);
191 EXPECT_NEAR(twoHanderChance, 11.0f, 0.01f);
192}

References ProcChanceTestHelper::CalculatePPMChance().