""" Edge case tests for calculate_duration() in web/models/database.py. These tests target the dateutil.parser fallback paths and timezone handling that are NOT covered by the existing test_database.py. """ from unittest.mock import patch from datetime import datetime, timezone, timedelta class TestDateutilFallbackPaths: """Tests for the dateutil.parser.parse fallback code paths.""" def test_completed_at_dateutil_fallback(self): """Weird completed_at format that fails fromisoformat but dateutil can parse.""" from local_deep_research.web.models.database import calculate_duration created_at = "2025-01-01T10:00:00+00:00" # Month name format — fromisoformat fails, dateutil parses it completed_at = "Jan 1, 2025 10:05:00 UTC" result = calculate_duration(created_at, completed_at) assert result is not None assert result == 300 # 5 minutes def test_created_at_dateutil_fallback(self): """Weird created_at format that fails standard parsing but dateutil can handle.""" from local_deep_research.web.models.database import calculate_duration created_at = "Jan 1, 2025 10:00:00 UTC" completed_at = "2025-01-01T10:02:00+00:00" result = calculate_duration(created_at, completed_at) assert result is not None assert result == 120 # 2 minutes def test_created_at_completely_unparseable_returns_none(self): """Completely unparseable created_at → returns None.""" from local_deep_research.web.models.database import calculate_duration result = calculate_duration( "not-a-date-at-all", "2025-01-01T10:00:00+00:00" ) assert result is None def test_completed_at_unparseable_falls_back_to_now(self): """Completely unparseable completed_at → falls back to current time.""" from local_deep_research.web.models.database import calculate_duration now = datetime.now(timezone.utc) created_at = (now - timedelta(seconds=60)).isoformat() # Patch dateutil.parser.parse to fail when called for the completed_at with patch( "dateutil.parser.parse", side_effect=Exception("Cannot parse") ): result = calculate_duration(created_at, "completely-invalid-!!!") # Falls back to datetime.now(UTC), so duration ≈ 60s assert result is not None assert 55 <= result <= 70 class TestTimezoneHandling: """Tests for timezone-aware vs timezone-naive mixing.""" def test_timezone_offset_format(self): """Timestamps with +HH:MM offset are handled.""" from local_deep_research.web.models.database import calculate_duration created_at = "2025-01-01T10:00:00+05:30" completed_at = "2025-01-01T10:30:00+05:30" result = calculate_duration(created_at, completed_at) assert result == 1800 # 30 minutes def test_different_timezone_offsets(self): """Timestamps with different timezone offsets are normalized.""" from local_deep_research.web.models.database import calculate_duration # Same absolute moment, different offsets created_at = "2025-01-01T10:00:00+00:00" completed_at = "2025-01-01T12:00:00+02:00" # Same as 10:00 UTC result = calculate_duration(created_at, completed_at) assert result == 0 # Same instant def test_negative_timezone_offset(self): """Negative timezone offset works correctly.""" from local_deep_research.web.models.database import calculate_duration created_at = "2025-01-01T10:00:00-05:00" # UTC 15:00 completed_at = "2025-01-01T16:00:00+00:00" # UTC 16:00 result = calculate_duration(created_at, completed_at) assert result == 3600 # 1 hour difference class TestSpaceSeparatedFormats: """Tests for space-separated timestamp formats.""" def test_space_separated_with_microseconds_and_tz(self): """Space-separated format with microseconds and timezone.""" from local_deep_research.web.models.database import calculate_duration # Include timezone to avoid naive datetime issues with astimezone created_at = "2025-01-01 10:00:00.123456+00:00" completed_at = "2025-01-01 10:01:00.654321+00:00" result = calculate_duration(created_at, completed_at) assert result is not None assert result == 60 or result == 61 def test_space_separated_without_microseconds_and_tz(self): """Space-separated format without microseconds, with timezone.""" from local_deep_research.web.models.database import calculate_duration created_at = "2025-01-01 10:00:00+00:00" completed_at = "2025-01-01 10:05:00+00:00" result = calculate_duration(created_at, completed_at) assert result == 300 # 5 minutes def test_space_to_t_replacement_fallback(self): """Space-separated with timezone falls back to replace(' ', 'T').""" from local_deep_research.web.models.database import calculate_duration # This has timezone info but no T separator — triggers the replace fallback created_at = "2025-01-01 10:00:00+00:00" completed_at = "2025-01-01 10:03:00+00:00" result = calculate_duration(created_at, completed_at) assert result == 180 # 3 minutes def test_iso_with_explicit_utc_offset(self): """ISO format with explicit UTC offset.""" from local_deep_research.web.models.database import calculate_duration created_at = "2025-01-01T10:00:00+00:00" completed_at = "2025-01-01T10:10:00+00:00" result = calculate_duration(created_at, completed_at) assert result == 600 # 10 minutes