# #region Test.Scheduler.EnsureAware [C:2] [TYPE Module] [SEMANTICS test,scheduler,datetime,utc] # @BRIEF Verify _ensure_aware contract — naive→UTC conversion, aware passthrough, None passthrough. # @RELATION BINDS_TO -> [TranslationScheduler._ensure_aware] # @TEST_EDGE naive_to_aware -> Naive datetime gets UTC tzinfo # @TEST_EDGE already_aware -> Aware datetime returned unchanged # @TEST_EDGE none_passthrough -> None returns None # @TEST_EDGE subtraction_works -> Conversion enables subtraction with datetime.now(UTC) # # @RATIONALE SQLAlchemy DateTime (without timezone=True) returns naive datetimes # even when stored as UTC. This module verifies the normalization # helper used throughout execute_scheduled_translation for safe # datetime arithmetic. from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from datetime import UTC, datetime, timedelta # #region TestEnsureAware [C:2] [TYPE Class] [SEMANTICS test,scheduler,datetime] # @BRIEF Tests for _ensure_aware() — naive-to-UTC conversion and edge cases. class TestEnsureAware: """_ensure_aware — convert naive DB datetime to UTC-aware for safe arithmetic.""" # #region test_naive_to_aware [C:2] [TYPE Function] [SEMANTICS test,datetime,naive] # @BRIEF Naive datetime gets UTC tzinfo attached. def test_naive_to_aware(self): from src.plugins.translate.scheduler import _ensure_aware naive = datetime(2024, 6, 15, 10, 30, 0) result = _ensure_aware(naive) assert result.tzinfo is not None assert result.tzinfo == UTC assert result == naive.replace(tzinfo=UTC) assert result.hour == 10 # no offset shift # #endregion test_naive_to_aware # #region test_already_aware_passthrough [C:2] [TYPE Function] [SEMANTICS test,datetime,aware] # @BRIEF Already UTC-aware datetime returned unchanged (same object). def test_already_aware_passthrough(self): from src.plugins.translate.scheduler import _ensure_aware aware = datetime(2024, 6, 15, 10, 30, 0, tzinfo=UTC) result = _ensure_aware(aware) assert result is aware # same object identity assert result.tzinfo == UTC # #endregion test_already_aware_passthrough # #region test_none_returns_none [C:2] [TYPE Function] [SEMANTICS test,datetime,none] # @BRIEF None input returns None. def test_none_returns_none(self): from src.plugins.translate.scheduler import _ensure_aware result = _ensure_aware(None) assert result is None # #endregion test_none_returns_none # #region test_subtraction_works [C:2] [TYPE Function] [SEMANTICS test,datetime,arithmetic] # @BRIEF Naive→aware conversion enables subtraction with datetime.now(UTC) # without TypeError (the original problem this function solves). def test_subtraction_works(self): from src.plugins.translate.scheduler import _ensure_aware naive = datetime(2024, 6, 15, 10, 0, 0) aware = _ensure_aware(naive) now = datetime.now(UTC) # This would raise TypeError without _ensure_aware: # TypeError: can't subtract offset-naive and offset-aware datetimes elapsed = now - aware assert isinstance(elapsed, timedelta) assert elapsed.total_seconds() > 0 # always positive vs past date # #endregion test_subtraction_works # #endregion TestEnsureAware # #endregion Test.Scheduler.EnsureAware