"""Tests for sun functionality.""" from datetime import datetime from unittest.mock import Mock, patch import pytest from agenda.sun import bristol, sunrise, sunset class TestBristol: """Test the bristol function.""" def test_bristol_returns_observer(self) -> None: """Test that bristol returns an ephem.Observer with correct coordinates.""" observer = bristol() # Check that it's an observer object with the right attributes assert hasattr(observer, 'lat') assert hasattr(observer, 'lon') # Check coordinates are set to Bristol assert str(observer.lat) == "51:27:16.2" # 51.4545 degrees assert str(observer.lon) == "-2:35:16.4" # -2.5879 degrees def test_bristol_observer_type(self) -> None: """Test that bristol returns the correct type.""" observer = bristol() # Should have methods needed for sun calculations assert hasattr(observer, 'next_rising') assert hasattr(observer, 'next_setting') class TestSunrise: """Test the sunrise function.""" @patch('agenda.sun.ephem') def test_sunrise_returns_datetime(self, mock_ephem: Mock) -> None: """Test that sunrise returns a datetime object.""" # Mock the observer and sun mock_observer = Mock() mock_sun = Mock() mock_ephem.Sun.return_value = mock_sun # Mock the rising calculation mock_rising = Mock() mock_rising.datetime.return_value = datetime(2024, 6, 15, 5, 30, 0) mock_observer.next_rising.return_value = mock_rising result = sunrise(mock_observer) assert isinstance(result, datetime) assert result == datetime(2024, 6, 15, 5, 30, 0) # Verify ephem calls mock_ephem.Sun.assert_called_once_with(mock_observer) mock_observer.next_rising.assert_called_once_with(mock_sun) def test_sunrise_with_real_observer(self) -> None: """Test sunrise with a real observer (integration test).""" observer = bristol() # Set a specific date for the observer observer.date = "2024/6/21" # Summer solstice result = sunrise(observer) # Should return a datetime object assert isinstance(result, datetime) # On summer solstice in Bristol, sunrise should be early morning assert 3 <= result.hour <= 6 # Roughly between 3-6 AM # Should be in 2024 assert result.year == 2024 def test_sunrise_different_dates(self) -> None: """Test sunrise for different dates.""" observer = bristol() # Summer solstice (longest day) observer.date = "2024/6/21" summer_sunrise = sunrise(observer) # Winter solstice (shortest day) observer.date = "2024/12/21" winter_sunrise = sunrise(observer) # Summer sunrise should be earlier than winter sunrise assert summer_sunrise.hour < winter_sunrise.hour class TestSunset: """Test the sunset function.""" @patch('agenda.sun.ephem') def test_sunset_returns_datetime(self, mock_ephem: Mock) -> None: """Test that sunset returns a datetime object.""" # Mock the observer and sun mock_observer = Mock() mock_sun = Mock() mock_ephem.Sun.return_value = mock_sun # Mock the setting calculation mock_setting = Mock() mock_setting.datetime.return_value = datetime(2024, 6, 15, 20, 30, 0) mock_observer.next_setting.return_value = mock_setting result = sunset(mock_observer) assert isinstance(result, datetime) assert result == datetime(2024, 6, 15, 20, 30, 0) # Verify ephem calls mock_ephem.Sun.assert_called_once_with(mock_observer) mock_observer.next_setting.assert_called_once_with(mock_sun) def test_sunset_with_real_observer(self) -> None: """Test sunset with a real observer (integration test).""" observer = bristol() # Set a specific date for the observer observer.date = "2024/6/21" # Summer solstice result = sunset(observer) # Should return a datetime object assert isinstance(result, datetime) # On summer solstice in Bristol, sunset should be in evening assert 19 <= result.hour <= 22 # Roughly between 7-10 PM # Should be in 2024 assert result.year == 2024 def test_sunset_different_dates(self) -> None: """Test sunset for different dates.""" observer = bristol() # Summer solstice (longest day) observer.date = "2024/6/21" summer_sunset = sunset(observer) # Winter solstice (shortest day) observer.date = "2024/12/21" winter_sunset = sunset(observer) # Summer sunset should be later than winter sunset assert summer_sunset.hour > winter_sunset.hour class TestSunIntegration: """Integration tests for sun calculations.""" def test_day_length_summer_vs_winter(self) -> None: """Test that summer days are longer than winter days.""" observer = bristol() # Summer solstice observer.date = "2024/6/21" summer_sunrise = sunrise(observer) summer_sunset = sunset(observer) summer_day_length = summer_sunset - summer_sunrise # Winter solstice observer.date = "2024/12/21" winter_sunrise = sunrise(observer) winter_sunset = sunset(observer) winter_day_length = winter_sunset - winter_sunrise # Summer day should be longer than winter day assert summer_day_length > winter_day_length def test_sunrise_before_sunset(self) -> None: """Test that sunrise is always before sunset.""" observer = bristol() observer.date = "2024/6/15" # Arbitrary date sunrise_time = sunrise(observer) sunset_time = sunset(observer) assert sunrise_time < sunset_time