mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-16 05:55:07 +00:00
fix(Core/Events): Fix multi-stage holiday events ending early on restart (#25032)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com> Co-authored-by: sudlud <sudlud@users.noreply.github.com>
This commit is contained in:
@@ -1236,3 +1236,156 @@ TEST_F(HolidayDateCalculatorTest, DarkmoonFaire_InHolidayRules)
|
||||
EXPECT_TRUE(foundMulgore) << "Darkmoon Faire Mulgore (375) should be in HolidayRules";
|
||||
EXPECT_TRUE(foundTerokkar) << "Darkmoon Faire Terokkar (376) should be in HolidayRules";
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FindStartTimeForStage tests
|
||||
// ============================================================================
|
||||
|
||||
class FindStartTimeForStageTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
// Helper to create a time_t from year/month/day/hour
|
||||
static time_t MakeTime(int year, int month, int day, int hour = 0)
|
||||
{
|
||||
std::tm t = {};
|
||||
t.tm_year = year - 1900;
|
||||
t.tm_mon = month - 1;
|
||||
t.tm_mday = day;
|
||||
t.tm_hour = hour;
|
||||
t.tm_isdst = -1;
|
||||
return mktime(&t);
|
||||
}
|
||||
|
||||
// Pack two dates into an array (rest zeroed)
|
||||
void PackTwoDates(uint32_t* dates, int y1, int m1, int d1, int y2, int m2, int d2)
|
||||
{
|
||||
std::tm t1 = {};
|
||||
t1.tm_year = y1 - 1900;
|
||||
t1.tm_mon = m1 - 1;
|
||||
t1.tm_mday = d1;
|
||||
t1.tm_isdst = -1;
|
||||
mktime(&t1);
|
||||
dates[0] = HolidayDateCalculator::PackDate(t1);
|
||||
|
||||
std::tm t2 = {};
|
||||
t2.tm_year = y2 - 1900;
|
||||
t2.tm_mon = m2 - 1;
|
||||
t2.tm_mday = d2;
|
||||
t2.tm_isdst = -1;
|
||||
mktime(&t2);
|
||||
dates[1] = HolidayDateCalculator::PackDate(t2);
|
||||
|
||||
for (int i = 2; i < 26; ++i)
|
||||
dates[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Stage 1 (no offset): curTime before event starts -> selects first date
|
||||
TEST_F(FindStartTimeForStageTest, Stage1_BeforeStart_SelectsFirstDate)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 3, 6, 2026, 4, 3);
|
||||
|
||||
time_t curTime = MakeTime(2026, 3, 1);
|
||||
time_t stageOffset = 0;
|
||||
uint32_t stageLengthMin = 72 * 60; // 72 hours = 3 days
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
EXPECT_EQ(result, MakeTime(2026, 3, 6));
|
||||
}
|
||||
|
||||
// Stage 1 (no offset): curTime during event -> selects current date
|
||||
TEST_F(FindStartTimeForStageTest, Stage1_DuringEvent_SelectsCurrentDate)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 3, 6, 2026, 4, 3);
|
||||
|
||||
time_t curTime = MakeTime(2026, 3, 7, 12); // mid-event
|
||||
time_t stageOffset = 0;
|
||||
uint32_t stageLengthMin = 72 * 60; // 3 days
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
EXPECT_EQ(result, MakeTime(2026, 3, 6));
|
||||
}
|
||||
|
||||
// Stage 1 (no offset): curTime after event ends -> selects next date
|
||||
TEST_F(FindStartTimeForStageTest, Stage1_AfterEnd_SelectsNextDate)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 3, 6, 2026, 4, 3);
|
||||
|
||||
time_t curTime = MakeTime(2026, 3, 20); // well past first event
|
||||
time_t stageOffset = 0;
|
||||
uint32_t stageLengthMin = 72 * 60; // 3 days
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
EXPECT_EQ(result, MakeTime(2026, 4, 3));
|
||||
}
|
||||
|
||||
// THE BUG: Stage 2 with stageOffset > 0, curTime in the window that the old
|
||||
// code would incorrectly skip (between startTime + stageLength and
|
||||
// startTime + stageOffset + stageLength). Without the fix, this would
|
||||
// return the NEXT occurrence's start instead of the current one.
|
||||
TEST_F(FindStartTimeForStageTest, Stage2_DuringLateWindow_SelectsCurrentDate)
|
||||
{
|
||||
// Simulate Darkmoon Faire:
|
||||
// Holiday starts Mar 6 (Friday, building phase)
|
||||
// Stage 1 (building): 72 hours = 3 days (Mar 6-9)
|
||||
// Stage 2 (active): 168 hours = 7 days (Mar 9-16)
|
||||
// Total holiday: Mar 6 - Mar 16 (10 days)
|
||||
// Next occurrence: Apr 3
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 3, 6, 2026, 4, 3);
|
||||
|
||||
time_t stageOffset = 72 * 3600; // Stage 1 = 72 hours in seconds
|
||||
uint32_t stageLengthMin = 168 * 60; // Stage 2 = 168 hours in minutes
|
||||
|
||||
// curTime = Mar 14 (day 8 of holiday, day 5 of stage 2)
|
||||
// Old bug: startTime(Mar 6) + 168h = Mar 13, so curTime > that -> SKIP to Apr 3!
|
||||
// Fixed: startTime(Mar 6) + 72h + 168h = Mar 16, so curTime < that -> correct
|
||||
time_t curTime = MakeTime(2026, 3, 14, 12);
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
// Should return Mar 6 + stageOffset = Mar 9 (stage 2 start)
|
||||
EXPECT_EQ(result, MakeTime(2026, 3, 6) + stageOffset);
|
||||
}
|
||||
|
||||
// Stage 2: curTime after entire holiday ends -> selects next occurrence
|
||||
TEST_F(FindStartTimeForStageTest, Stage2_AfterHolidayEnds_SelectsNextDate)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 3, 6, 2026, 4, 3);
|
||||
|
||||
time_t stageOffset = 72 * 3600;
|
||||
uint32_t stageLengthMin = 168 * 60;
|
||||
|
||||
// curTime = Mar 20 (well past the entire holiday)
|
||||
time_t curTime = MakeTime(2026, 3, 20);
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
EXPECT_EQ(result, MakeTime(2026, 4, 3) + stageOffset);
|
||||
}
|
||||
|
||||
// No valid dates -> returns 0
|
||||
TEST_F(FindStartTimeForStageTest, NoDates_ReturnsZero)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
time_t curTime = MakeTime(2026, 6, 1);
|
||||
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, 0, 168 * 60, curTime);
|
||||
EXPECT_EQ(result, 0);
|
||||
}
|
||||
|
||||
// All dates in the past -> returns 0
|
||||
TEST_F(FindStartTimeForStageTest, AllDatesPast_ReturnsZero)
|
||||
{
|
||||
uint32_t dates[26] = {};
|
||||
PackTwoDates(dates, 2026, 1, 5, 2026, 2, 6);
|
||||
|
||||
time_t stageOffset = 0;
|
||||
uint32_t stageLengthMin = 72 * 60;
|
||||
|
||||
time_t curTime = MakeTime(2026, 6, 1); // way after both dates
|
||||
time_t result = HolidayDateCalculator::FindStartTimeForStage(dates, 26, stageOffset, stageLengthMin, curTime);
|
||||
EXPECT_EQ(result, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user