From 6f533ae6200c8d1b9da118e433c9917cead687d0 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 10 Jul 2022 15:44:58 -0700 Subject: [PATCH] Refactors mothweek check (#68280) * Refactors mothweek check Mothweek HAS SIDE EFFECTS Checking it on a day that causes a week offset will currently cause that week offset to persist That's dumb. Also it's not very expansive, only covers a slim set of possibilities. Instead, lets build something to generate all passing days over a period of time, maybe 3 months out of 2 years. Then we'll crosscheck that against some predecided "ok" dates If either list disagrees with each other, we'll fail. That way we can't miss an edgecase. or have issues with side effects I like this pattern. --- code/__HELPERS/time.dm | 29 +++++++++++++++++++++++++---- code/modules/holiday/holidays.dm | 17 +++++++++++++++++ code/modules/unit_tests/holidays.dm | 22 +++++++++++++++++----- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 9edb40bfd03..9c57f2334c8 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -59,17 +59,38 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) if (SUNDAY) return 7 -///Returns the first day of the given year and month in number format, from 1 (monday) - 7 (sunday). -/proc/first_day_of_month(year, month) +///Returns an integer in ISO format 1 (Monday) - 7 (Sunday) as a string day +/proc/iso_to_weekday(ddd) + switch (ddd) + if (1) + return MONDAY + if (2) + return TUESDAY + if (3) + return WEDNESDAY + if (4) + return THURSDAY + if (5) + return FRIDAY + if (6) + return SATURDAY + if (7) + return SUNDAY + +/// Returns the day (mon, tues, wen...) in number format, 1 (monday) - 7 (sunday) from the passed in date (year, month, day) +/// All inputs are expected indexed at 1 +/proc/day_of_month(year, month, day) // https://en.wikipedia.org/wiki/Zeller%27s_congruence var/m = month < 3 ? month + 12 : month // month (march = 3, april = 4...february = 14) var/K = year % 100 // year of century var/J = round(year / 100) // zero-based century - // day 0-6 saturday to sunday: - var/h = (1 + round(13 * (m + 1) / 5) + K + round(K / 4) + round(J / 4) - 2 * J) % 7 + // day 0-6 saturday to friday: + var/h = (day + round(13 * (m + 1) / 5) + K + round(K / 4) + round(J / 4) - 2 * J) % 7 //convert to ISO 1-7 monday first format return ((h + 5) % 7) + 1 +/proc/first_day_of_month(year, month) + return day_of_month(year, month, 1) //Takes a value of time in deciseconds. //Returns a text value of that number in hours, minutes, or seconds. diff --git a/code/modules/holiday/holidays.dm b/code/modules/holiday/holidays.dm index dddb1dd30cc..aed67f1bba9 100644 --- a/code/modules/holiday/holidays.dm +++ b/code/modules/holiday/holidays.dm @@ -794,3 +794,20 @@ /datum/holiday/easter/getStationPrefix() return pick("Fluffy","Bunny","Easter","Egg") + +/// Takes a holiday datum, a starting month, ending month, max amount of days to test in, and min/max year as input +/// Returns a list in the form list("yyyy/m/d", ...) representing all days the holiday runs on in the tested range +/proc/poll_holiday(datum/holiday/path, min_month, max_month, min_year, max_year, max_day) + var/list/deets = list() + for(var/year in min_year to max_year) + for(var/month in min_month to max_month) + for(var/day in 1 to max_day) + var/datum/holiday/new_day = new path() + if(new_day.shouldCelebrate(day, month, year, iso_to_weekday(day_of_month(year, month, day)))) + deets += "[year]/[month]/[day]" + return deets + +/// Does the same as [/proc/poll_holiday], but prints the output to admins instead of returning it +/proc/print_holiday(datum/holiday/path, min_month, max_month, min_year, max_year, max_day) + var/list/deets = poll_holiday(path, min_month, max_month, min_year, max_year, max_day) + message_admins("The accepted dates for [path] in the input range [min_year]-[max_year]/[min_month]-[max_month]/1-[max_day] are [deets.Join("\n")]") diff --git a/code/modules/unit_tests/holidays.dm b/code/modules/unit_tests/holidays.dm index b1b1d5c82f1..ce48c4e1d7d 100644 --- a/code/modules/unit_tests/holidays.dm +++ b/code/modules/unit_tests/holidays.dm @@ -29,8 +29,20 @@ TEST_ASSERT(new_year.shouldCelebrate(2, JANUARY, 1983, SUNDAY), "January 2, 1983 was not New Year.") /datum/unit_test/moth_week_2020/Run() - var/datum/holiday/nth_week/moth/moth = new - TEST_ASSERT(moth.shouldCelebrate(18, JULY, 2020, SATURDAY), "July 18, 2020 was not Moth Week.") - TEST_ASSERT(moth.shouldCelebrate(20, JULY, 2020, MONDAY), "July 20, 2020 was not Moth Week.") - TEST_ASSERT(moth.shouldCelebrate(24, JULY, 2020, FRIDAY), "July 24, 2020 was not Moth Week.") - TEST_ASSERT(moth.shouldCelebrate(26, JULY, 2020, SUNDAY), "July 26, 2020 was not Moth Week.") + // We expect 2 year's worth of moth week, falling on the last full week of july + // We test ahead and behind just in case something's fucked + // Both lists are in the form yyyy/m/d + var/list/produced_moth_days = poll_holiday(/datum/holiday/nth_week/moth, 6, 8, 2020, 2021, 31) + var/list/predicted_moth_days = list() + for(var/day in 18 to 26) // Last full week of July 2020 + predicted_moth_days += "2020/7/[day]" + for(var/day in 17 to 25) // Last full week of July 2021 + predicted_moth_days += "2021/7/[day]" + var/list/unexpected_moths = produced_moth_days - predicted_moth_days + for(var/date in unexpected_moths) + TEST_FAIL("[date] was improperly Moth Week") + + var/list/missing_moths = predicted_moth_days - produced_moth_days + for(var/date in missing_moths) + TEST_FAIL("[date] was not Moth Week") +