using CursorLang.Core.Threading; using CursorLang.Tests.Shared; namespace CursorLang.Core.Tests.Threading; /// /// The timer the agent has instead of a dispatcher timer. /// /// /// It ticks on the message loop, so everything here runs on the pump thread — a timer /// started on one thread and awaited on another would never be seen to fire. /// public sealed class MessageTimerTests { [Fact] public void A_started_timer_ticks() { int ticks = 0; Pump.Run(() => { using var timer = new MessageTimer(); timer.Interval = TimeSpan.FromMilliseconds(15); timer.Tick += (_, _) => ticks++; timer.Start(); Pump.WaitFor(() => ticks > 0, "the timer ticked"); }); } [Fact] public void A_timer_keeps_ticking_until_it_is_stopped() { var ticks = 0; Pump.Run(() => { using var timer = new MessageTimer(); timer.Interval = TimeSpan.FromMilliseconds(15); timer.Tick += (_, _) => ticks++; timer.Start(); Pump.WaitFor(() => ticks >= 3, "the timer ticked more than once"); }); } // A stopped countdown does not go off, however long the loop runs afterwards [Fact] public void A_stopped_timer_does_not_tick() { var ticks = 0; Pump.Run(() => { using var timer = new MessageTimer(); timer.Interval = TimeSpan.FromMilliseconds(10); timer.Tick += (_, _) => ticks++; timer.Start(); timer.Stop(); Pump.Pause(TimeSpan.FromMilliseconds(80)); }); Assert.Equal(0, ticks); } // Restarting means from zero, so a countdown kept short by repeated restarts // never reaches its end [Fact] public void Restarting_begins_the_countdown_again() { var ticks = 0; Pump.Run(() => { using var timer = new MessageTimer(); timer.Interval = TimeSpan.FromMilliseconds(60); timer.Tick += (_, _) => ticks++; for (var i = 0; i < 6; i++) { timer.Start(); Pump.Pause(TimeSpan.FromMilliseconds(20)); } Assert.Equal(0, ticks); Pump.WaitFor(() => ticks > 0, "left alone, the timer reached its end"); }); } [Fact] public void Closing_the_timer_ends_the_ticking() { var ticks = 0; Pump.Run(() => { var timer = new MessageTimer { Interval = TimeSpan.FromMilliseconds(15) }; timer.Tick += (_, _) => ticks++; timer.Start(); Pump.WaitFor(() => ticks > 0, "the timer ticked"); timer.Dispose(); int seen = ticks; Pump.Pause(TimeSpan.FromMilliseconds(80)); Assert.Equal(seen, ticks); }); } [Fact] public void A_timer_that_was_never_started_says_so() { Pump.Run(() => { using var timer = new MessageTimer(); Assert.False(timer.IsRunning); timer.Start(); Assert.True(timer.IsRunning); timer.Stop(); Assert.False(timer.IsRunning); }); } }