test: pre-start sweeps cover prior nominal occurrences (clamped monthly day, prior-year yearly, prior 2nd-Tuesday); MONTHLY_WEEKDAY post-end probe; end==start single-day for all six types
This commit is contained in:
@@ -108,11 +108,26 @@ BOUNDARY_RULES = [
|
|||||||
def test_no_firing_before_start_date(index) -> None:
|
def test_no_firing_before_start_date(index) -> None:
|
||||||
fixture = BOUNDARY_RULES[index]
|
fixture = BOUNDARY_RULES[index]
|
||||||
rule = ScheduleRule(**fixture["kwargs"])
|
rule = ScheduleRule(**fixture["kwargs"])
|
||||||
first = fixture["first_firing"]
|
|
||||||
# Every day BEFORE start_date never fires — sweep the week before
|
|
||||||
# plus the full prior month.
|
|
||||||
before_start = _d(rule.start_date)
|
before_start = _d(rule.start_date)
|
||||||
sweep_from = before_start - datetime.timedelta(days=30)
|
# The sweep must cover the shape's PRIOR nominal occurrence:
|
||||||
|
# - MONTHLY_DAY: the prior month's clamped day (e.g. Feb 28/31)
|
||||||
|
# - YEARLY: the prior year's nominal day
|
||||||
|
# - WEEKLY/CUSTOM_DAYS: the prior week's matching weekday
|
||||||
|
# - MONTHLY_WEEKDAY: the prior month's nth weekday
|
||||||
|
if rule.rule_type is RuleType.MONTHLY_DAY:
|
||||||
|
sweep_from = _month_end(2026, 2) # Feb 28, a nominal clamp day
|
||||||
|
elif rule.rule_type is RuleType.YEARLY:
|
||||||
|
sweep_from = datetime.date(
|
||||||
|
_d(rule.start_date).year - 1, rule.month, rule.day_of_month
|
||||||
|
)
|
||||||
|
elif rule.rule_type is RuleType.MONTHLY_WEEKDAY:
|
||||||
|
sweep_from = _tuesday(2026, 2, 2) # prior month's 2nd Tuesday
|
||||||
|
elif rule.rule_type is RuleType.WEEKLY:
|
||||||
|
sweep_from = before_start - datetime.timedelta(days=7)
|
||||||
|
elif rule.rule_type is RuleType.CUSTOM_DAYS:
|
||||||
|
sweep_from = before_start - datetime.timedelta(days=7)
|
||||||
|
else:
|
||||||
|
sweep_from = before_start - datetime.timedelta(days=30)
|
||||||
cursor = sweep_from
|
cursor = sweep_from
|
||||||
while cursor < before_start:
|
while cursor < before_start:
|
||||||
assert occurs_on(rule, cursor) is False, cursor
|
assert occurs_on(rule, cursor) is False, cursor
|
||||||
@@ -176,6 +191,15 @@ def test_no_firing_after_end_date_at_nominal_shapes() -> None:
|
|||||||
assert occurs_on(rule_weekly, _d("2026-09-29")) is True
|
assert occurs_on(rule_weekly, _d("2026-09-29")) is True
|
||||||
assert occurs_on(rule_weekly, _d("2026-10-06")) is False
|
assert occurs_on(rule_weekly, _d("2026-10-06")) is False
|
||||||
|
|
||||||
|
rule_monthly_weekday = ScheduleRule(
|
||||||
|
rule_type=RuleType.MONTHLY_WEEKDAY, nth_weekday=2,
|
||||||
|
nth_weekday_weekday=1, start_date="2026-03-03",
|
||||||
|
end_date="2026-10-05",
|
||||||
|
)
|
||||||
|
# The next nominal second Tuesday (Oct 13) is past end_date: silent.
|
||||||
|
assert occurs_on(rule_monthly_weekday, _d("2026-09-08")) is True
|
||||||
|
assert occurs_on(rule_monthly_weekday, _d("2026-10-13")) is False
|
||||||
|
|
||||||
|
|
||||||
def test_no_end_date_means_no_upper_bound() -> None:
|
def test_no_end_date_means_no_upper_bound() -> None:
|
||||||
"""A rule without end_date keeps firing arbitrarily far out — for
|
"""A rule without end_date keeps firing arbitrarily far out — for
|
||||||
@@ -241,12 +265,31 @@ def test_end_date_equal_to_start_date_allows_one_day_window() -> None:
|
|||||||
assert occurs_on(weekly, _d("2026-03-10")) is True
|
assert occurs_on(weekly, _d("2026-03-10")) is True
|
||||||
assert occurs_on(weekly, _d("2026-03-17")) is False
|
assert occurs_on(weekly, _d("2026-03-17")) is False
|
||||||
|
|
||||||
|
custom = ScheduleRule(
|
||||||
|
rule_type=RuleType.CUSTOM_DAYS, weekday_set={2, 4},
|
||||||
|
start_date="2026-03-11", end_date="2026-03-11",
|
||||||
|
)
|
||||||
|
# Mar 11 2026 is a Wednesday: fires. Next Wed (18) is out of window.
|
||||||
|
assert _d("2026-03-11").weekday() == 2
|
||||||
|
assert occurs_on(custom, _d("2026-03-11")) is True
|
||||||
|
assert occurs_on(custom, _d("2026-03-18")) is False
|
||||||
|
|
||||||
monthly_day = ScheduleRule(
|
monthly_day = ScheduleRule(
|
||||||
rule_type=RuleType.MONTHLY_DAY, day_of_month=15,
|
rule_type=RuleType.MONTHLY_DAY, day_of_month=15,
|
||||||
start_date="2026-03-15", end_date="2026-03-15",
|
start_date="2026-03-15", end_date="2026-03-15",
|
||||||
)
|
)
|
||||||
assert occurs_on(monthly_day, _d("2026-03-15")) is True
|
assert occurs_on(monthly_day, _d("2026-03-15")) is True
|
||||||
|
|
||||||
|
monthly_weekday = ScheduleRule(
|
||||||
|
rule_type=RuleType.MONTHLY_WEEKDAY, nth_weekday=2,
|
||||||
|
nth_weekday_weekday=1, start_date="2026-03-10",
|
||||||
|
end_date="2026-03-10",
|
||||||
|
)
|
||||||
|
# Mar 10 2026 is the second Tuesday: the one-day window admits it.
|
||||||
|
assert _d("2026-03-10").weekday() == 1
|
||||||
|
assert occurs_on(monthly_weekday, _d("2026-03-10")) is True
|
||||||
|
assert occurs_on(monthly_weekday, _d("2026-04-14")) is False
|
||||||
|
|
||||||
yearly = ScheduleRule(
|
yearly = ScheduleRule(
|
||||||
rule_type=RuleType.YEARLY, month=3, day_of_month=15,
|
rule_type=RuleType.YEARLY, month=3, day_of_month=15,
|
||||||
start_date="2026-03-15", end_date="2026-03-15",
|
start_date="2026-03-15", end_date="2026-03-15",
|
||||||
|
|||||||
Reference in New Issue
Block a user