Files
azerothcore-wotlk/src/test/server/game/Spells/SpellProcPPMModifierTest.cpp
blinkysc 4599f26ae9 refactor(Core/Spells): QAston proc system (#24233)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
Co-authored-by: QAston <qaston@gmail.com>
Co-authored-by: joschiwald <joschiwald@online.de>
Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
Co-authored-by: blinkysc <your-github-email@example.com>
Co-authored-by: Tereneckla <Tereneckla@users.noreply.github.com>
Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com>
2026-02-18 08:31:53 -03:00

400 lines
13 KiB
C++

/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file SpellProcPPMModifierTest.cpp
* @brief Unit tests for SPELLMOD_PROC_PER_MINUTE modifier application
*
* Tests the logic from Unit.cpp:10378-10390:
* - Base PPM calculation without modifiers
* - Flat PPM modifier application
* - Percent PPM modifier application
* - GetSpellModOwner() null handling
* - SpellProto null handling
*/
#include "ProcChanceTestHelper.h"
#include "ProcEventInfoHelper.h"
#include "gtest/gtest.h"
using namespace testing;
class SpellProcPPMModifierTest : public ::testing::Test
{
protected:
void SetUp() override {}
// Standard weapon speeds for testing
static constexpr uint32 DAGGER_SPEED = 1400; // 1.4 sec
static constexpr uint32 SWORD_SPEED = 2500; // 2.5 sec
static constexpr uint32 TWO_HANDED_SPEED = 3300; // 3.3 sec
};
// =============================================================================
// Base PPM Calculation (No Modifiers)
// =============================================================================
TEST_F(SpellProcPPMModifierTest, BasePPM_NoModifiers)
{
ProcChanceTestHelper::PPMModifierConfig config;
// Default config: no modifiers, has spell mod owner and spell proto
float basePPM = 6.0f;
// With 2500ms weapon: (2500 * 6) / 600 = 25%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 25.0f, 0.01f)
<< "Base PPM 6.0 with 2.5s weapon should give 25% chance";
}
TEST_F(SpellProcPPMModifierTest, BasePPM_DifferentWeaponSpeeds)
{
ProcChanceTestHelper::PPMModifierConfig config;
float basePPM = 6.0f;
// Fast dagger: (1400 * 6) / 600 = 14%
float daggerChance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
DAGGER_SPEED, basePPM, config);
EXPECT_NEAR(daggerChance, 14.0f, 0.01f);
// Slow 2H: (3300 * 6) / 600 = 33%
float twoHandChance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
TWO_HANDED_SPEED, basePPM, config);
EXPECT_NEAR(twoHandChance, 33.0f, 0.01f);
}
TEST_F(SpellProcPPMModifierTest, BasePPM_ZeroPPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, 0.0f, config);
EXPECT_EQ(chance, 0.0f)
<< "Zero PPM should return 0% chance";
}
TEST_F(SpellProcPPMModifierTest, BasePPM_NegativePPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, -5.0f, config);
EXPECT_EQ(chance, 0.0f)
<< "Negative PPM should return 0% chance";
}
// =============================================================================
// Flat Modifier Tests - SPELLMOD_FLAT for SPELLMOD_PROC_PER_MINUTE
// =============================================================================
TEST_F(SpellProcPPMModifierTest, FlatModifier_IncreasesPPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = 2.0f; // +2 PPM
float basePPM = 6.0f;
// Modified PPM: 6 + 2 = 8
// Chance: (2500 * 8) / 600 = 33.33%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 33.33f, 0.1f)
<< "Flat +2 PPM modifier should increase chance from 25% to 33.33%";
}
TEST_F(SpellProcPPMModifierTest, FlatModifier_DecreasesPPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = -3.0f; // -3 PPM
float basePPM = 6.0f;
// Modified PPM: 6 - 3 = 3
// Chance: (2500 * 3) / 600 = 12.5%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 12.5f, 0.1f)
<< "Flat -3 PPM modifier should decrease chance from 25% to 12.5%";
}
TEST_F(SpellProcPPMModifierTest, FlatModifier_ReducesToZero)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = -10.0f; // Would reduce to -4 PPM
float basePPM = 6.0f;
// Modified PPM: 6 - 10 = -4 (negative)
// Formula still applies: (2500 * -4) / 600 = negative
// But the check at start for PPM <= 0 happens before modifiers
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
// Note: In the real code, negative results are possible after modifiers
// The helper doesn't clamp the final result
EXPECT_LT(chance, 0.0f)
<< "Extreme negative modifier can produce negative chance";
}
// =============================================================================
// Percent Modifier Tests - SPELLMOD_PCT for SPELLMOD_PROC_PER_MINUTE
// =============================================================================
TEST_F(SpellProcPPMModifierTest, PercentModifier_50PercentIncrease)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.pctModifier = 1.5f; // 150% = 50% increase
float basePPM = 6.0f;
// Modified PPM: 6 * 1.5 = 9
// Chance: (2500 * 9) / 600 = 37.5%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 37.5f, 0.1f)
<< "50% PPM increase should raise chance from 25% to 37.5%";
}
TEST_F(SpellProcPPMModifierTest, PercentModifier_50PercentDecrease)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.pctModifier = 0.5f; // 50% = 50% decrease
float basePPM = 6.0f;
// Modified PPM: 6 * 0.5 = 3
// Chance: (2500 * 3) / 600 = 12.5%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 12.5f, 0.1f)
<< "50% PPM decrease should lower chance from 25% to 12.5%";
}
TEST_F(SpellProcPPMModifierTest, PercentModifier_DoublesPPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.pctModifier = 2.0f; // 200%
float basePPM = 6.0f;
// Modified PPM: 6 * 2 = 12
// Chance: (2500 * 12) / 600 = 50%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 50.0f, 0.1f)
<< "100% PPM increase should double chance to 50%";
}
// =============================================================================
// Combined Modifiers Tests
// =============================================================================
TEST_F(SpellProcPPMModifierTest, CombinedModifiers_FlatThenPercent)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = 2.0f; // +2 PPM first
config.pctModifier = 1.5f; // Then 50% increase
float basePPM = 6.0f;
// Flat first: 6 + 2 = 8
// Percent: 8 * 1.5 = 12
// Chance: (2500 * 12) / 600 = 50%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 50.0f, 0.1f)
<< "Flat +2 then 50% increase should result in 50% chance";
}
TEST_F(SpellProcPPMModifierTest, CombinedModifiers_BothIncrease)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = 4.0f; // +4 PPM
config.pctModifier = 1.25f; // 25% increase
float basePPM = 6.0f;
// Flat first: 6 + 4 = 10
// Percent: 10 * 1.25 = 12.5
// Chance: (2500 * 12.5) / 600 = 52.08%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 52.08f, 0.1f);
}
// =============================================================================
// No SpellModOwner Tests - GetSpellModOwner() returns null
// =============================================================================
TEST_F(SpellProcPPMModifierTest, NoSpellModOwner_ModifiersIgnored)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.hasSpellModOwner = false; // GetSpellModOwner() returns null
config.flatModifier = 10.0f; // Would significantly change result
config.pctModifier = 2.0f;
float basePPM = 6.0f;
// Without spell mod owner, modifiers are NOT applied
// Chance: (2500 * 6) / 600 = 25%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 25.0f, 0.1f)
<< "Without spell mod owner, modifiers should be ignored";
}
// =============================================================================
// No SpellProto Tests - spellProto is null
// =============================================================================
TEST_F(SpellProcPPMModifierTest, NoSpellProto_ModifiersIgnored)
{
ProcChanceTestHelper::PPMModifierConfig config;
config.hasSpellProto = false; // spellProto is null
config.flatModifier = 10.0f;
config.pctModifier = 2.0f;
float basePPM = 6.0f;
// Without spell proto, modifiers are NOT applied
// Chance: (2500 * 6) / 600 = 25%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, basePPM, config);
EXPECT_NEAR(chance, 25.0f, 0.1f)
<< "Without spell proto, modifiers should be ignored";
}
// =============================================================================
// Real Spell Scenarios
// =============================================================================
TEST_F(SpellProcPPMModifierTest, Scenario_OmenOfClarity_BasePPM)
{
// Omen of Clarity: 6 PPM
ProcChanceTestHelper::PPMModifierConfig config;
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, 6.0f, config);
EXPECT_NEAR(chance, 25.0f, 0.1f)
<< "Omen of Clarity base chance with 2.5s weapon";
}
TEST_F(SpellProcPPMModifierTest, Scenario_OmenOfClarity_WithTalent)
{
// Hypothetical talent that increases Omen of Clarity PPM by 2
ProcChanceTestHelper::PPMModifierConfig config;
config.flatModifier = 2.0f;
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, 6.0f, config);
EXPECT_NEAR(chance, 33.33f, 0.1f)
<< "Omen of Clarity with +2 PPM talent";
}
TEST_F(SpellProcPPMModifierTest, Scenario_WindfuryWeapon_FastWeapon)
{
// Windfury Weapon: 2 PPM with fast weapon
ProcChanceTestHelper::PPMModifierConfig config;
// Fast 1.5s weapon: (1500 * 2) / 600 = 5%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
1500, 2.0f, config);
EXPECT_NEAR(chance, 5.0f, 0.1f)
<< "Windfury with 1.5s weapon";
}
TEST_F(SpellProcPPMModifierTest, Scenario_WindfuryWeapon_SlowWeapon)
{
// Windfury Weapon: 2 PPM with slow weapon
ProcChanceTestHelper::PPMModifierConfig config;
// Slow 3.6s weapon: (3600 * 2) / 600 = 12%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
3600, 2.0f, config);
EXPECT_NEAR(chance, 12.0f, 0.1f)
<< "Windfury with 3.6s weapon";
}
TEST_F(SpellProcPPMModifierTest, Scenario_JudgementOfLight_HighPPM)
{
// Judgement of Light: 15 PPM (very high)
ProcChanceTestHelper::PPMModifierConfig config;
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, 15.0f, config);
// (2500 * 15) / 600 = 62.5%
EXPECT_NEAR(chance, 62.5f, 0.1f)
<< "Judgement of Light with 2.5s weapon";
}
// =============================================================================
// Edge Cases
// =============================================================================
TEST_F(SpellProcPPMModifierTest, EdgeCase_VeryFastWeapon)
{
ProcChanceTestHelper::PPMModifierConfig config;
// 1.0s weapon (very fast): (1000 * 6) / 600 = 10%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
1000, 6.0f, config);
EXPECT_NEAR(chance, 10.0f, 0.1f);
}
TEST_F(SpellProcPPMModifierTest, EdgeCase_VerySlowWeapon)
{
ProcChanceTestHelper::PPMModifierConfig config;
// 4.0s weapon (very slow): (4000 * 6) / 600 = 40%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
4000, 6.0f, config);
EXPECT_NEAR(chance, 40.0f, 0.1f);
}
TEST_F(SpellProcPPMModifierTest, EdgeCase_VeryHighPPM)
{
ProcChanceTestHelper::PPMModifierConfig config;
// 60 PPM: (2500 * 60) / 600 = 250% (over 100%, can happen)
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
SWORD_SPEED, 60.0f, config);
EXPECT_NEAR(chance, 250.0f, 0.1f)
<< "Very high PPM can exceed 100% chance";
}
TEST_F(SpellProcPPMModifierTest, EdgeCase_ZeroWeaponSpeed)
{
ProcChanceTestHelper::PPMModifierConfig config;
// Zero weapon speed should result in 0%
float chance = ProcChanceTestHelper::CalculatePPMChanceWithModifiers(
0, 6.0f, config);
EXPECT_EQ(chance, 0.0f);
}