Track 1.1 of master plan: expand from sexp-only tests to cover DTOs, HTTP signatures, HMAC auth, URL utilities, Jinja filters, calendar helpers, config freeze, activity bus registry, parse utilities, sexp helpers, error classes, and jinja bridge render API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
"""Tests for calendar date helper functions."""
|
|
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
from shared.utils.calendar_helpers import add_months, build_calendar_weeks
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# add_months
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestAddMonths:
|
|
def test_same_year(self):
|
|
assert add_months(2025, 3, 2) == (2025, 5)
|
|
|
|
def test_next_year(self):
|
|
assert add_months(2025, 11, 2) == (2026, 1)
|
|
|
|
def test_subtract(self):
|
|
assert add_months(2025, 3, -2) == (2025, 1)
|
|
|
|
def test_subtract_prev_year(self):
|
|
assert add_months(2025, 1, -1) == (2024, 12)
|
|
|
|
def test_add_twelve(self):
|
|
assert add_months(2025, 6, 12) == (2026, 6)
|
|
|
|
def test_subtract_twelve(self):
|
|
assert add_months(2025, 6, -12) == (2024, 6)
|
|
|
|
def test_large_delta(self):
|
|
assert add_months(2025, 1, 25) == (2027, 2)
|
|
|
|
def test_zero_delta(self):
|
|
assert add_months(2025, 7, 0) == (2025, 7)
|
|
|
|
def test_december_to_january(self):
|
|
assert add_months(2025, 12, 1) == (2026, 1)
|
|
|
|
def test_january_to_december(self):
|
|
assert add_months(2025, 1, -1) == (2024, 12)
|
|
|
|
def test_subtract_large(self):
|
|
assert add_months(2025, 3, -15) == (2023, 12)
|
|
|
|
def test_month_boundaries(self):
|
|
# Every month +1
|
|
for m in range(1, 12):
|
|
y, nm = add_months(2025, m, 1)
|
|
assert nm == m + 1
|
|
assert y == 2025
|
|
y, nm = add_months(2025, 12, 1)
|
|
assert nm == 1
|
|
assert y == 2026
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_calendar_weeks
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestBuildCalendarWeeks:
|
|
def test_returns_list_of_weeks(self):
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
assert isinstance(weeks, list)
|
|
assert len(weeks) >= 4 # at least 4 weeks in any month
|
|
assert len(weeks) <= 6 # at most 6 weeks
|
|
|
|
def test_each_week_has_7_days(self):
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
for week in weeks:
|
|
assert len(week) == 7
|
|
|
|
def test_day_dict_structure(self):
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
day = weeks[0][0]
|
|
assert "date" in day
|
|
assert "in_month" in day
|
|
assert "is_today" in day
|
|
assert isinstance(day["date"], date)
|
|
assert isinstance(day["in_month"], bool)
|
|
assert isinstance(day["is_today"], bool)
|
|
|
|
def test_in_month_flag(self):
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
june_days = [d for w in weeks for d in w if d["in_month"]]
|
|
assert len(june_days) == 30 # June has 30 days
|
|
|
|
def test_february_leap_year(self):
|
|
weeks = build_calendar_weeks(2024, 2)
|
|
feb_days = [d for w in weeks for d in w if d["in_month"]]
|
|
assert len(feb_days) == 29
|
|
|
|
def test_february_non_leap_year(self):
|
|
weeks = build_calendar_weeks(2025, 2)
|
|
feb_days = [d for w in weeks for d in w if d["in_month"]]
|
|
assert len(feb_days) == 28
|
|
|
|
def test_starts_on_monday(self):
|
|
"""Calendar should start on Monday (firstweekday=0)."""
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
first_day = weeks[0][0]["date"]
|
|
assert first_day.weekday() == 0 # Monday
|
|
|
|
def test_is_today_flag(self):
|
|
"""The today flag should be True for exactly one day (or zero if not in month range)."""
|
|
# Use a fixed known date - mock datetime.now
|
|
from datetime import datetime, timezone
|
|
fixed_now = datetime(2025, 6, 15, tzinfo=timezone.utc)
|
|
with patch("shared.utils.calendar_helpers.datetime") as mock_dt:
|
|
mock_dt.now.return_value = fixed_now
|
|
mock_dt.side_effect = lambda *a, **kw: datetime(*a, **kw)
|
|
weeks = build_calendar_weeks(2025, 6)
|
|
today_days = [d for w in weeks for d in w if d["is_today"]]
|
|
assert len(today_days) == 1
|
|
assert today_days[0]["date"] == date(2025, 6, 15)
|