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()
{