diff --git a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs index 47408f85..bb6000b0 100644 --- a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs @@ -40,14 +40,28 @@ public INotificationHandler On /// /// Initializes the with a random time. /// - public MockTimeSystem() : this(Testing.TimeProvider.Random()) + public MockTimeSystem() : this(Testing.TimeProvider.Random(), options => options) + { + } + + /// + /// Initializes the with a random time. + /// + public MockTimeSystem(Func options) : this(Testing.TimeProvider.Random(), options) + { + } + + /// + /// Initializes the with the specified . + /// + public MockTimeSystem(DateTime time) : this(Testing.TimeProvider.Use(time), options => options) { } /// /// Initializes the with the specified . /// - public MockTimeSystem(DateTime time) : this(Testing.TimeProvider.Use(time)) + public MockTimeSystem(DateTime time, Func options) : this(Testing.TimeProvider.Use(time), options) { } @@ -65,16 +79,26 @@ public MockTimeSystem(ITimeProvider timeProvider) : this( /// /// Initializes the with the specified . /// - public MockTimeSystem(ITimeProviderFactory timeProvider) + public MockTimeSystem(ITimeProviderFactory timeProvider) : this(timeProvider, options => options) + { + } + + /// + /// Initializes the with the specified and the given . + /// + public MockTimeSystem(ITimeProviderFactory timeProvider, Func options) { + MockTimeSystemOptions initialization = new(); + initialization = options(initialization); + _callbackHandler = new NotificationHandler(this); TimeProvider = timeProvider.Create(_callbackHandler.InvokeTimeChanged); _dateTimeMock = new DateTimeMock(this, _callbackHandler); _stopwatchFactoryMock = new StopwatchFactoryMock(this); - _threadMock = new ThreadMock(this, _callbackHandler); - _taskMock = new TaskMock(this, _callbackHandler); + _threadMock = new ThreadMock(this, _callbackHandler, initialization.AutoAdvance); + _taskMock = new TaskMock(this, _callbackHandler, initialization.AutoAdvance); #if FEATURE_PERIODIC_TIMER - _periodicTimerFactoryMock = new PeriodicTimerFactoryMock(this); + _periodicTimerFactoryMock = new PeriodicTimerFactoryMock(this, initialization.AutoAdvance); #endif _timerFactoryMock = new TimerFactoryMock(this); } @@ -122,4 +146,24 @@ public MockTimeSystem WithTimerStrategy(ITimerStrategy timerStrategy) _timerFactoryMock.SetTimerStrategy(timerStrategy); return this; } + + /// + /// The initialization options for the . + /// + public class MockTimeSystemOptions + { + /// + /// Flag indicating if the time should automatically be advanced when waiting for timers, tasks or threads to complete. + /// + internal bool AutoAdvance { get; private set; } = true; + + /// + /// Disables automatic advancement of the time when waiting for timers, tasks or threads to complete. + /// + public MockTimeSystemOptions DisableAutoAdvance() + { + AutoAdvance = false; + return this; + } + } } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerFactoryMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerFactoryMock.cs index cacd40ea..bc7ac412 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerFactoryMock.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerFactoryMock.cs @@ -9,10 +9,12 @@ namespace Testably.Abstractions.Testing.TimeSystem; internal sealed class PeriodicTimerFactoryMock : IPeriodicTimerFactory { private readonly MockTimeSystem _mockTimeSystem; + private readonly bool _autoAdvance; - internal PeriodicTimerFactoryMock(MockTimeSystem timeSystem) + internal PeriodicTimerFactoryMock(MockTimeSystem timeSystem, bool autoAdvance) { _mockTimeSystem = timeSystem; + _autoAdvance = autoAdvance; } #region IPeriodicTimerFactory Members @@ -22,7 +24,7 @@ internal PeriodicTimerFactoryMock(MockTimeSystem timeSystem) /// public IPeriodicTimer New(TimeSpan period) - => new PeriodicTimerMock(_mockTimeSystem, period); + => new PeriodicTimerMock(_mockTimeSystem, period, _autoAdvance); /// public IPeriodicTimer Wrap(PeriodicTimer timer) diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerMock.cs index 06f3e9a1..37cecd03 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerMock.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/PeriodicTimerMock.cs @@ -12,13 +12,15 @@ internal sealed class PeriodicTimerMock : IPeriodicTimer private bool _isDisposed; private DateTime _lastTime; private readonly MockTimeSystem _timeSystem; + private readonly bool _autoAdvance; internal PeriodicTimerMock(MockTimeSystem timeSystem, - TimeSpan period) + TimeSpan period, bool autoAdvance) { ThrowIfPeriodIsInvalid(period, nameof(period)); _timeSystem = timeSystem; + _autoAdvance = autoAdvance; _lastTime = _timeSystem.DateTime.UtcNow; Period = period; } @@ -60,8 +62,20 @@ public void Dispose() DateTime nextTime = _lastTime + Period; if (nextTime > now) { - _timeSystem.TimeProvider.AdvanceBy(nextTime - now); - _lastTime = nextTime; + if (_autoAdvance) + { + _timeSystem.TimeProvider.AdvanceBy(nextTime - now); + _lastTime = nextTime; + } + else + { + using var onTimeChanged = _timeSystem.On + .TimeChanged(predicate: t => t >= nextTime); + await onTimeChanged.WaitAsync( + timeout: Timeout.InfiniteTimeSpan, + cancellationToken: cancellationToken).ConfigureAwait(false); + _lastTime = _timeSystem.DateTime.UtcNow; + } } else { diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TaskMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TaskMock.cs index 6c1c0739..92e94ad2 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TaskMock.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/TaskMock.cs @@ -8,14 +8,17 @@ namespace Testably.Abstractions.Testing.TimeSystem; internal sealed class TaskMock : ITask { + private readonly bool _autoAdvance; private readonly NotificationHandler _callbackHandler; private readonly MockTimeSystem _mockTimeSystem; internal TaskMock(MockTimeSystem timeSystem, - NotificationHandler callbackHandler) + NotificationHandler callbackHandler, + bool autoAdvance) { _mockTimeSystem = timeSystem; _callbackHandler = callbackHandler; + _autoAdvance = autoAdvance; } #region ITask Members @@ -53,7 +56,11 @@ public Task Delay(TimeSpan delay, CancellationToken cancellationToken) throw ExceptionFactory.TaskWasCanceled(); } - _mockTimeSystem.TimeProvider.AdvanceBy(delay); + if (_autoAdvance) + { + _mockTimeSystem.TimeProvider.AdvanceBy(delay); + } + _callbackHandler.InvokeTaskDelayCallbacks(delay); return Task.CompletedTask; } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/ThreadMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/ThreadMock.cs index c60fe5eb..8c4f6027 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/ThreadMock.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/ThreadMock.cs @@ -7,14 +7,17 @@ namespace Testably.Abstractions.Testing.TimeSystem; internal sealed class ThreadMock : IThread { + private readonly bool _autoAdvance; private readonly NotificationHandler _callbackHandler; private readonly MockTimeSystem _mockTimeSystem; internal ThreadMock(MockTimeSystem timeSystem, - NotificationHandler callbackHandler) + NotificationHandler callbackHandler, + bool autoAdvance) { _mockTimeSystem = timeSystem; _callbackHandler = callbackHandler; + _autoAdvance = autoAdvance; } #region IThread Members @@ -33,7 +36,11 @@ public void Sleep(TimeSpan timeout) throw ExceptionFactory.ThreadSleepOutOfRange(nameof(timeout)); } - _mockTimeSystem.TimeProvider.AdvanceBy(timeout); + if (_autoAdvance) + { + _mockTimeSystem.TimeProvider.AdvanceBy(timeout); + } + Thread.Yield(); _callbackHandler.InvokeThreadSleepCallbacks(timeout); } diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net10.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net10.0.txt index 3c0b5f07..676379c4 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net10.0.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net10.0.txt @@ -102,8 +102,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; } @@ -115,6 +118,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net6.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net6.0.txt index fbce856f..62046999 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net6.0.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net6.0.txt @@ -101,8 +101,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; } @@ -113,6 +116,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net8.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net8.0.txt index 134c6b66..152f4e39 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net8.0.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net8.0.txt @@ -102,8 +102,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; } @@ -115,6 +118,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt index c25db5c5..9beb7d98 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_net9.0.txt @@ -102,8 +102,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; } @@ -115,6 +118,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.0.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.0.txt index 5fb73555..0412c0e3 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.0.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.0.txt @@ -96,8 +96,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; } @@ -108,6 +111,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.1.txt b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.1.txt index 4ab99954..322b6837 100644 --- a/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.1.txt +++ b/Tests/Api/Testably.Abstractions.Api.Tests/Expected/Testably.Abstractions.Testing_netstandard2.1.txt @@ -96,8 +96,11 @@ namespace Testably.Abstractions.Testing { public MockTimeSystem() { } public MockTimeSystem(System.DateTime time) { } + public MockTimeSystem(System.Func options) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProvider timeProvider) { } public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider) { } + public MockTimeSystem(System.DateTime time, System.Func options) { } + public MockTimeSystem(Testably.Abstractions.Testing.TimeSystem.ITimeProviderFactory timeProvider, System.Func options) { } public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; } public Testably.Abstractions.Testing.TimeSystem.INotificationHandler On { get; } public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; } @@ -108,6 +111,11 @@ namespace Testably.Abstractions.Testing public Testably.Abstractions.Testing.TimeSystem.ITimerHandler TimerHandler { get; } public override string ToString() { } public Testably.Abstractions.Testing.MockTimeSystem WithTimerStrategy(Testably.Abstractions.Testing.TimeSystem.ITimerStrategy timerStrategy) { } + public class MockTimeSystemOptions + { + public MockTimeSystemOptions() { } + public Testably.Abstractions.Testing.MockTimeSystem.MockTimeSystemOptions DisableAutoAdvance() { } + } } public static class Notification { diff --git a/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs b/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs index 23ecba82..33a20408 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/MockTimeSystemTests.cs @@ -1,10 +1,25 @@ -using System.Threading; +using aweXpect.Chronology; +using System.Collections.Generic; +using System.Threading; using Testably.Abstractions.Testing.Tests.TestHelpers; +using Testably.Abstractions.TimeSystem; namespace Testably.Abstractions.Testing.Tests; public class MockTimeSystemTests { + [Test] + public async Task Delay_DisabledAutoAdvance_ShouldNotChangeTime() + { + MockTimeSystem timeSystem = new(o => o.DisableAutoAdvance()); + DateTime before = timeSystem.DateTime.Now; + + await timeSystem.Task.Delay(5.Seconds(), TestContext.Current!.Execution.CancellationToken); + + DateTime after = timeSystem.DateTime.Now; + await That(after).IsEqualTo(before); + } + [Test] public async Task Delay_Infinite_ShouldNotThrowException() { @@ -71,6 +86,86 @@ public async Task await That(actualDifference).IsEqualTo(expectedDifference); } +#if FEATURE_PERIODIC_TIMER + [Test] + public async Task PeriodicTimer_DisabledAutoAdvance_ShouldNotAdvanceTime() + { + MockTimeSystem timeSystem = new(o => o.DisableAutoAdvance()); + int tickCount = 0; + using CancellationTokenSource cts = + CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current!.Execution + .CancellationToken); + CancellationToken token = cts.Token; + _ = Task.Run(async () => + { + using IPeriodicTimer periodicTimer = timeSystem.PeriodicTimer.New(1.Seconds()); + while (await periodicTimer.WaitForNextTickAsync(token)) + { + tickCount++; + } + }, token); + + await Task.Delay(50.Milliseconds(), token); + await That(tickCount).IsEqualTo(0); + cts.Cancel(); + } +#endif + +#if FEATURE_PERIODIC_TIMER + [Test] + [Arguments(5)] + public async Task PeriodicTimer_DisabledAutoAdvance_ShouldTriggerWhenTimeIsManuallyAdvanced(int amount) + { + var time = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); + MockTimeSystem timeSystem = new(time, o => o.DisableAutoAdvance()); + List tickTimes = []; + using CancellationTokenSource cts = CancellationTokenSource + .CreateLinkedTokenSource(TestContext.Current!.Execution.CancellationToken); + cts.CancelAfter(30.Seconds()); + CancellationToken token = cts.Token; + using SemaphoreSlim waitStarted = new(0, amount); + using SemaphoreSlim tickObserved = new(0, amount); + + Task backgroundTask = Task.Run(async () => + { + using IPeriodicTimer periodicTimer = timeSystem.PeriodicTimer.New(1.Seconds()); + for (int i = 0; i < amount; i++) + { + ValueTask waitForTickTask = periodicTimer.WaitForNextTickAsync(token); + // ReSharper disable once AccessToDisposedClosure + waitStarted.Release(); + _ = await waitForTickTask; + tickTimes.Add(timeSystem.DateTime.UtcNow); + // ReSharper disable once AccessToDisposedClosure + tickObserved.Release(); + } + }, token); + + for (int i = 0; i < amount; i++) + { + await waitStarted.WaitAsync(token); + timeSystem.TimeProvider.AdvanceBy(2.Seconds()); + await tickObserved.WaitAsync(token); + } + + await backgroundTask; + await That(tickTimes).HasCount(amount); + await That(tickTimes).All().Satisfy(t => t.Second % 2 == 0); + } +#endif + + [Test] + public async Task Sleep_DisabledAutoAdvance_ShouldNotChangeTime() + { + MockTimeSystem timeSystem = new(DateTime.Now, o => o.DisableAutoAdvance()); + DateTime before = timeSystem.DateTime.Now; + + timeSystem.Thread.Sleep(5.Seconds()); + + DateTime after = timeSystem.DateTime.Now; + await That(after).IsEqualTo(before); + } + [Test] public async Task Sleep_Infinite_ShouldNotThrowException() {