@@ -3039,3 +3039,58 @@ def fake_cache_bool(dummy: object, setting: str) -> bool | None:
30393039 with patch ("aiofiles.threadpool.sync_open" , return_value = mock_file_stream ):
30403040 await stick .disconnect ()
30413041 await asyncio .sleep (1 )
3042+
3043+ @freeze_time ("2026-01-31 10:30:00" , real_asyncio = True )
3044+ @pytest .mark .asyncio
3045+ async def test_clock_synchronize_month_overflow (
3046+ self , monkeypatch : pytest .MonkeyPatch
3047+ ) -> None :
3048+ """Test clock_synchronize handles month-end date rollover correctly.
3049+
3050+ Regression test for issue `#399`: ensures that when the Circle's day_of_week
3051+ differs from the current weekday near month-end, the date calculation
3052+ doesn't attempt an invalid day value (e.g., Jan 32).
3053+ """
3054+ mock_serial = MockSerial (None )
3055+ monkeypatch .setattr (
3056+ pw_connection_manager ,
3057+ "create_serial_connection" ,
3058+ mock_serial .mock_connection ,
3059+ )
3060+ monkeypatch .setattr (pw_sender , "STICK_TIME_OUT" , 0.2 )
3061+ monkeypatch .setattr (pw_requests , "NODE_TIME_OUT" , 2.0 )
3062+
3063+ stick = pw_stick .Stick ("test_port" , cache_enabled = False )
3064+ await stick .connect ()
3065+ await stick .initialize ()
3066+ await stick .discover_nodes (load = False )
3067+ await self ._wait_for_scan (stick )
3068+
3069+ # Get a Circle node
3070+ circle_node = stick .nodes .get ("0098765432101234" )
3071+ assert circle_node is not None
3072+ await circle_node .load ()
3073+
3074+ # Mock CircleClockGetRequest.send() to return a response where
3075+ # day_of_week is Saturday (5) while frozen time is Friday (4), Jan 31
3076+ async def mock_clock_get_send (self ):
3077+ response = pw_responses .CircleClockResponse ()
3078+ response .timestamp = dt .now (tz = UTC )
3079+ # Set day_of_week to Saturday (5), requiring +1 day from Friday Jan 31
3080+ # Old code: Jan 31 + 1 = day 32 (ValueError)
3081+ # New code: Jan 31 + timedelta(days=1) = Feb 1 (correct)
3082+ response .day_of_week .value = 5 # Saturday
3083+ response .time .value = dt .now (tz = UTC ).time ()
3084+ return response
3085+
3086+ monkeypatch .setattr (
3087+ pw_requests .CircleClockGetRequest ,
3088+ "send" ,
3089+ mock_clock_get_send ,
3090+ )
3091+
3092+ # This should not raise ValueError about invalid day
3093+ result = await circle_node .clock_synchronize ()
3094+ assert result is True
3095+
3096+ await stick .disconnect ()
0 commit comments