# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Unit tests for `modules.shared.dateRange`. Pure-Python, no DB / no API. """ from datetime import date, datetime, time as dtTime import pytest from fastapi import HTTPException from modules.shared.dateRange import ( daysInRange, isoDateRangeToLocalEpoch, parseIsoDate, parseIsoDateRange, ) class TestParseIsoDate: def test_validIsoDate(self): assert parseIsoDate("2026-04-15", "dateFrom") == date(2026, 4, 15) def test_emptyStringRaises400(self): with pytest.raises(HTTPException) as exc: parseIsoDate("", "dateFrom") assert exc.value.status_code == 400 assert "dateFrom" in exc.value.detail def test_invalidFormatRaises400(self): with pytest.raises(HTTPException) as exc: parseIsoDate("15.04.2026", "dateTo") assert exc.value.status_code == 400 assert "dateTo" in exc.value.detail assert "15.04.2026" in exc.value.detail def test_nonStringRaises400(self): with pytest.raises(HTTPException) as exc: parseIsoDate(None, "dateFrom") # type: ignore[arg-type] assert exc.value.status_code == 400 class TestParseIsoDateRange: def test_validRange(self): f, t = parseIsoDateRange("2026-04-01", "2026-04-15") assert f == date(2026, 4, 1) assert t == date(2026, 4, 15) def test_sameDayIsValid(self): f, t = parseIsoDateRange("2026-04-15", "2026-04-15") assert f == t def test_invertedRangeRaises400(self): with pytest.raises(HTTPException) as exc: parseIsoDateRange("2026-04-15", "2026-04-01") assert exc.value.status_code == 400 assert "dateFrom must be <= dateTo" in exc.value.detail class TestIsoDateRangeToLocalEpoch: def test_inclusiveEndOfDay(self): """`dateTo` boundary covers full last day (23:59:59.999999 local).""" fromTs, toTs = isoDateRangeToLocalEpoch("2026-04-15", "2026-04-15") startOfDay = datetime.combine(date(2026, 4, 15), dtTime.min).timestamp() endOfDay = datetime.combine(date(2026, 4, 15), dtTime.max).timestamp() assert fromTs == startOfDay assert toTs == endOfDay # Single-day range covers ~24h - 1 microsecond. assert (toTs - fromTs) > (24 * 3600 - 1) def test_multiDayRange(self): fromTs, toTs = isoDateRangeToLocalEpoch("2026-04-01", "2026-04-03") # Three local days, end-inclusive: ~3 * 86400 seconds (- 1us). assert 3 * 86400 - 1 < (toTs - fromTs) < 3 * 86400 + 1 def test_invalidRaises400(self): with pytest.raises(HTTPException): isoDateRangeToLocalEpoch("not-a-date", "2026-04-03") class TestDaysInRange: def test_singleDayIsOne(self): assert daysInRange("2026-04-15", "2026-04-15") == 1 def test_threeDaysInclusive(self): assert daysInRange("2026-04-01", "2026-04-03") == 3 def test_yearSpan(self): assert daysInRange("2026-01-01", "2026-12-31") == 365 def test_invertedRangeRaises400(self): with pytest.raises(HTTPException): daysInRange("2026-04-15", "2026-04-01")