diff --git a/Feature.Flags.props b/Feature.Flags.props index 6507c5114..1852d3b8d 100644 --- a/Feature.Flags.props +++ b/Feature.Flags.props @@ -23,7 +23,6 @@ $(DefineConstants);FEATURE_RANDOM_ADVANCED $(DefineConstants);FEATURE_FILESYSTEMWATCHER_ADVANCED $(DefineConstants);FEATURE_EXCEPTION_HRESULT - $(DefineConstants);FEATURE_TIMER_COUNT $(DefineConstants);FEATURE_ZIPFILE_NET7 $(DefineConstants);FEATURE_FILESYSTEM_NET7 $(DefineConstants);FEATURE_FILESYSTEM_SAFEFILEHANDLE diff --git a/Source/Testably.Abstractions.Interface/ITimeSystem.cs b/Source/Testably.Abstractions.Interface/ITimeSystem.cs index 8f41f8449..20d684226 100644 --- a/Source/Testably.Abstractions.Interface/ITimeSystem.cs +++ b/Source/Testably.Abstractions.Interface/ITimeSystem.cs @@ -21,9 +21,4 @@ public interface ITimeSystem /// Abstractions for . /// IThread Thread { get; } - - /// - /// Abstractions for . - /// - ITimerFactory Timer { get; } } diff --git a/Source/Testably.Abstractions.Interface/TimeSystem/ITimer.cs b/Source/Testably.Abstractions.Interface/TimeSystem/ITimer.cs deleted file mode 100644 index a27fe49c9..000000000 --- a/Source/Testably.Abstractions.Interface/TimeSystem/ITimer.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Threading; - -namespace Testably.Abstractions.TimeSystem; - -/// -/// Abstractions for . -/// -public interface ITimer : ITimeSystemEntity, IDisposable -#if FEATURE_ASYNC_DISPOSABLE - , IAsyncDisposable -#endif -{ - /// - bool Change(int dueTime, int period); - - /// - bool Change(long dueTime, long period); - - /// - bool Change(TimeSpan dueTime, TimeSpan period); - - /// - bool Dispose(WaitHandle notifyObject); -} diff --git a/Source/Testably.Abstractions.Interface/TimeSystem/ITimerFactory.cs b/Source/Testably.Abstractions.Interface/TimeSystem/ITimerFactory.cs deleted file mode 100644 index 6b9538b4e..000000000 --- a/Source/Testably.Abstractions.Interface/TimeSystem/ITimerFactory.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Threading; - -namespace Testably.Abstractions.TimeSystem; - -/// -/// Factory for abstracting creation of . -/// -public interface ITimerFactory : ITimeSystemEntity -{ -#if FEATURE_TIMER_COUNT - /// - long ActiveCount { get; } -#endif - - /// - ITimer New(TimerCallback callback); - - /// - ITimer New(TimerCallback callback, object? state, int dueTime, int period); - - /// - ITimer New(TimerCallback callback, object? state, long dueTime, long period); - - /// - ITimer New(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period); - - /// - /// Wraps the to the testable . - /// - ITimer Wrap(Timer timer); -} diff --git a/Source/Testably.Abstractions.Testing/Helpers/ExceptionFactory.cs b/Source/Testably.Abstractions.Testing/Helpers/ExceptionFactory.cs index de20fd546..0eea2925c 100644 --- a/Source/Testably.Abstractions.Testing/Helpers/ExceptionFactory.cs +++ b/Source/Testably.Abstractions.Testing/Helpers/ExceptionFactory.cs @@ -19,9 +19,6 @@ public static NotSupportedException NotSupportedSafeFileHandle() => new( "You cannot mock a safe file handle in the mocked file system without registering a strategy explicitly. Use `MockFileSystem.WithSafeFileHandleStrategy`!"); - public static NotSupportedException NotSupportedTimerWrapping() - => new("You cannot wrap an existing Timer in the MockTimeSystem instance!"); - public static ArgumentException SearchPatternCannotContainTwoDots() => new( "Search pattern cannot contain \"..\" to move up directories and can be contained only internally in file/directory names, as in \"a..b\"."); @@ -241,15 +238,6 @@ internal static PlatformNotSupportedException UnixFileModeNotSupportedOnThisPlat { #if FEATURE_EXCEPTION_HRESULT HResult = -2146233031 -#endif - }; - - public static ArgumentOutOfRangeException TimerArgumentOutOfRange(string propertyName) - => new(propertyName, - "Number must be either non-negative and less than or equal to Int32.MaxValue or -1") - { -#if FEATURE_EXCEPTION_HRESULT - HResult = -2146233086 #endif }; } diff --git a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs index 9ca89bebc..347942218 100644 --- a/Source/Testably.Abstractions.Testing/MockTimeSystem.cs +++ b/Source/Testably.Abstractions.Testing/MockTimeSystem.cs @@ -22,16 +22,10 @@ public INotificationHandler On /// public ITimeProvider TimeProvider { get; } - /// - /// The handler for mocked timers. - /// - public ITimerHandler TimerHandler => _timerMock; - private readonly NotificationHandler _callbackHandler; private readonly DateTimeMock _dateTimeMock; private readonly TaskMock _taskMock; private readonly ThreadMock _threadMock; - private readonly TimerFactoryMock _timerMock; /// /// Initializes the with a random time. @@ -57,7 +51,6 @@ public MockTimeSystem(ITimeProvider timeProvider) _dateTimeMock = new DateTimeMock(this, _callbackHandler); _threadMock = new ThreadMock(this, _callbackHandler); _taskMock = new TaskMock(this, _callbackHandler); - _timerMock = new TimerFactoryMock(this, _callbackHandler); } #region ITimeSystem Members @@ -74,19 +67,5 @@ public ITask Task public IThread Thread => _threadMock; - /// - public ITimerFactory Timer - => _timerMock; - #endregion - - /// - /// Specifies the to use when dealing with timers. - /// - /// The timer strategy. - public MockTimeSystem WithTimerStrategy(ITimerStrategy timerStrategy) - { - _timerMock.SetTimerStrategy(timerStrategy); - return this; - } } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/INotificationHandler.cs b/Source/Testably.Abstractions.Testing/TimeSystem/INotificationHandler.cs index 7ad35f14b..df9a1abd1 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/INotificationHandler.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/INotificationHandler.cs @@ -56,17 +56,4 @@ Notification.IAwaitableCallback TaskDelay( Notification.IAwaitableCallback ThreadSleep( Action? callback = null, Func? predicate = null); - - /// - /// Callback executed when a timer callback was executed. - /// - /// The callback to execute after the Thread.Sleep was called. - /// - /// (optional) A predicate used to filter which callbacks should be notified.
- /// If set to (default value) all callbacks are notified. - /// - /// An to un-register the callback on dispose. - Notification.IAwaitableCallback TimerExecuted( - Action? callback = null, - Func? predicate = null); } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerHandler.cs b/Source/Testably.Abstractions.Testing/TimeSystem/ITimerHandler.cs deleted file mode 100644 index 92a33d66a..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// The timer handler gives access to all registered timers. -/// -public interface ITimerHandler -{ - /// - /// Gets the timer associated with the specified . - /// - /// A zero-based incremented integer according to the order of the timer registration. - ITimerMock this[int index] { get; } -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/ITimerMock.cs deleted file mode 100644 index 051ac3d77..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerMock.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// Additional abstractions for a mocked timer to simplify testing.
-/// Implements . -///
-public interface ITimerMock : ITimer -{ - /// - /// Blocks the current thread, until the timer is executed times.
- /// Throws an - ///
- /// The number of execution cycles the thread is blocked. - /// - /// The timeout for blocking the current thread.
- /// Throws an when the timeout is expired. - /// - /// - /// A callback to execute after the execution count, before the next execution is triggered. - /// - /// The method parameter allows stopping the timer by calling . - /// - /// - /// - /// When the expires before the timer is executed - /// times. - /// - ITimerMock Wait(int executionCount = 1, int timeout = 10000, - Action? callback = null); -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerStrategy.cs b/Source/Testably.Abstractions.Testing/TimeSystem/ITimerStrategy.cs deleted file mode 100644 index 6ead4badc..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/ITimerStrategy.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading; - -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// The strategy how to handle mocked timers for testing. -/// -public interface ITimerStrategy -{ - /// - /// The timer mode. - /// - TimerMode Mode { get; } - - /// - /// Flag indicating, if exceptions in the should be swallowed or thrown. - /// - /// The real will crash the application in case of an exception in the - /// . - /// - bool SwallowExceptions { get; } -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/NotificationHandler.cs b/Source/Testably.Abstractions.Testing/TimeSystem/NotificationHandler.cs index 5c64c4aa6..2a363fe30 100644 --- a/Source/Testably.Abstractions.Testing/TimeSystem/NotificationHandler.cs +++ b/Source/Testably.Abstractions.Testing/TimeSystem/NotificationHandler.cs @@ -13,9 +13,6 @@ private readonly Notification.INotificationFactory private readonly Notification.INotificationFactory _threadSleepCallbacks = Notification.CreateFactory(); - private readonly Notification.INotificationFactory - _timerExecutedCallbacks = Notification.CreateFactory(); - #region INotificationHandler Members /// @@ -36,12 +33,6 @@ public Notification.IAwaitableCallback ThreadSleep( Func? predicate = null) => _threadSleepCallbacks.RegisterCallback(callback, predicate); - /// - public Notification.IAwaitableCallback TimerExecuted( - Action? callback = null, - Func? predicate = null) - => _timerExecutedCallbacks.RegisterCallback(callback, predicate); - #endregion public void InvokeDateTimeReadCallbacks(DateTime now) @@ -52,7 +43,4 @@ public void InvokeTaskDelayCallbacks(TimeSpan delay) public void InvokeThreadSleepCallbacks(TimeSpan timeout) => _threadSleepCallbacks.InvokeCallbacks(timeout); - - public void InvokeTimerExecutedCallbacks(TimerExecution timerExecution) - => _timerExecutedCallbacks.InvokeCallbacks(timerExecution); } diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerExecution.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerExecution.cs deleted file mode 100644 index bc4513097..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerExecution.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; - -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// A container for notifying the execution of a timer callback. -/// -public class TimerExecution -{ - /// - /// The time when the callback finished executing. - /// - public DateTime Time { get; } - - /// - /// The (zero-based) execution counter. - /// - public int ExecutionCount { get; } - - /// - /// The mocked timer. - /// - public ITimerMock Timer { get; } - - /// - /// The exception thrown during this timer execution. - /// - public Exception? Exception { get; } - - internal TimerExecution(DateTime time, int executionCount, ITimerMock timer, - Exception? exception) - { - Time = time; - ExecutionCount = executionCount; - Timer = timer; - Exception = exception; - } -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerFactoryMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerFactoryMock.cs deleted file mode 100644 index 54b067cd6..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerFactoryMock.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.IO; -using System.Threading; -using Testably.Abstractions.Testing.Helpers; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Testing.TimeSystem; - -internal sealed class TimerFactoryMock : ITimerFactory, ITimerHandler -{ - private readonly NotificationHandler _callbackHandler; - private readonly MockTimeSystem _mockTimeSystem; - private ITimerStrategy _timerStrategy; - private readonly ConcurrentDictionary _timers = new(); - private int _nextIndex = -1; - - internal TimerFactoryMock(MockTimeSystem timeSystem, - NotificationHandler callbackHandler) - { - _mockTimeSystem = timeSystem; - _callbackHandler = callbackHandler; - _timerStrategy = TimerStrategy.Default; - } - - #region ITimerFactory Members - - /// - public ITimeSystem TimeSystem - => _mockTimeSystem; - - #endregion - -#if FEATURE_TIMER_COUNT - /// - public long ActiveCount => _timers.Count; -#endif - - /// - public ITimer New(TimerCallback callback) - { - TimerMock timerMock = new(_mockTimeSystem, _callbackHandler, _timerStrategy, - callback, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); - return RegisterTimerMock(timerMock); - } - - /// - public ITimer New(TimerCallback callback, object? state, int dueTime, int period) - { - TimerMock timerMock = new(_mockTimeSystem, _callbackHandler, _timerStrategy, - callback, state, TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period)); - return RegisterTimerMock(timerMock); - } - - /// - public ITimer New(TimerCallback callback, object? state, long dueTime, long period) - { - TimerMock timerMock = new(_mockTimeSystem, _callbackHandler, _timerStrategy, - callback, state, TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period)); - return RegisterTimerMock(timerMock); - } - - /// - public ITimer New(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period) - { - TimerMock timerMock = new(_mockTimeSystem, _callbackHandler, _timerStrategy, - callback, state, dueTime, period); - return RegisterTimerMock(timerMock); - } - - /// - public ITimer Wrap(Timer timer) - => throw ExceptionFactory.NotSupportedTimerWrapping(); - - private TimerMock RegisterTimerMock(TimerMock timerMock) - { - int index = Interlocked.Increment(ref _nextIndex); - if (_timers.TryAdd(index, timerMock)) - { - timerMock.RegisterOnDispose(() => _timers.TryRemove(index, out _)); - } - - return timerMock; - } - - internal ITimerHandler SetTimerStrategy(ITimerStrategy timerStrategy) - { - _timerStrategy = timerStrategy; - return this; - } - - /// - public ITimerMock this[int index] - => _timers[index]; -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs deleted file mode 100644 index 928fb929c..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMock.cs +++ /dev/null @@ -1,329 +0,0 @@ -using System; -using System.Threading; -using Testably.Abstractions.Testing.Helpers; -using Testably.Abstractions.TimeSystem; -#if FEATURE_ASYNC_DISPOSABLE -using System.Threading.Tasks; -#endif - -namespace Testably.Abstractions.Testing.TimeSystem; - -internal sealed class TimerMock : ITimerMock -{ - private readonly TimerCallback _callback; - private readonly NotificationHandler _callbackHandler; - private CancellationTokenSource? _cancellationTokenSource; - private readonly ManualResetEventSlim _continueEvent = new(); - private CountdownEvent? _countdownEvent; - private TimeSpan _dueTime; - private Exception? _exception; - private int _executionCount; - private bool _isDisposed; - private readonly object _lock = new(); - private readonly MockTimeSystem _mockTimeSystem; - private Action? _onDispose; - private TimeSpan _period; - private readonly object? _state; - private readonly ITimerStrategy _timerStrategy; - - internal TimerMock(MockTimeSystem timeSystem, - NotificationHandler callbackHandler, - ITimerStrategy timerStrategy, - TimerCallback callback, - object? state, - TimeSpan dueTime, - TimeSpan period) - { - if (dueTime.TotalMilliseconds < -1) - { - throw ExceptionFactory.TimerArgumentOutOfRange(nameof(dueTime)); - } - - if (period.TotalMilliseconds < -1) - { - throw new ArgumentOutOfRangeException(nameof(period)); - } - - _mockTimeSystem = timeSystem; - _callbackHandler = callbackHandler; - _timerStrategy = timerStrategy; - _callback = callback; - _state = state; - _dueTime = dueTime; - _period = period; - if (_timerStrategy.Mode == TimerMode.StartImmediately) - { - Start(); - } - } - - #region ITimerMock Members - - /// - public ITimeSystem TimeSystem - => _mockTimeSystem; - -#if FEATURE_ASYNC_DISPOSABLE - /// - public ValueTask DisposeAsync() - { - Dispose(); -#if NETSTANDARD2_1 - return new ValueTask(); -#else - return ValueTask.CompletedTask; -#endif - } -#endif - - /// - public void Dispose() - { - if (!_isDisposed) - { - _isDisposed = true; - Stop(); - _onDispose?.Invoke(); - lock (_lock) - { - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = null; - } - } - } - - /// - public bool Change(int dueTime, int period) - => Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period)); - - /// - public bool Change(long dueTime, long period) - => Change(TimeSpan.FromMilliseconds(dueTime), TimeSpan.FromMilliseconds(period)); - - /// - public bool Change(TimeSpan dueTime, TimeSpan period) - { - if (_isDisposed) - { - throw new ObjectDisposedException("Cannot access a disposed object."); - } - - if (dueTime.TotalMilliseconds < -1) - { - throw ExceptionFactory.TimerArgumentOutOfRange(nameof(dueTime)); - } - - if (period.TotalMilliseconds < -1) - { - throw new ArgumentOutOfRangeException(nameof(period)); - } - - try - { - Stop(); - _dueTime = dueTime; - _period = period; - Start(); - return true; - } - catch (Exception) - { - return false; - } - } - - /// - public bool Dispose(WaitHandle notifyObject) - { - if (_isDisposed) - { - return false; - } - - switch (notifyObject) - { - case Mutex m: - m.WaitOne(); - Dispose(); - m.ReleaseMutex(); - break; - case Semaphore s: - s.WaitOne(); - Dispose(); - s.Release(); - break; - case EventWaitHandle e: - Dispose(); - e.Set(); - break; - default: - throw new NotSupportedException("The wait handle is not of any supported type!"); - } - - return true; - } - - /// - public ITimerMock Wait( - int executionCount = 1, - int timeout = 10000, - Action? callback = null) - { - if (executionCount <= 0) - { - throw new ArgumentOutOfRangeException(nameof(executionCount)); - } - - if (timeout < -1) - { - throw new ArgumentOutOfRangeException(nameof(timeout)); - } - - if (_timerStrategy.Mode != TimerMode.StartImmediately) - { - Start(); - } - - try - { - _countdownEvent = new CountdownEvent(executionCount - _executionCount); - if (!_countdownEvent.Wait(timeout)) - { - throw new TimeoutException( - $"The execution count {executionCount} was not reached in {timeout}ms."); - } - } - catch (ArgumentOutOfRangeException) - { - // In case of an ArgumentOutOfRangeException, the executionCount is already reached. - } - - if (_exception != null) - { - throw _exception; - } - - callback?.Invoke(this); - _continueEvent.Set(); - - return this; - } - - #endregion - - internal void RegisterOnDispose(Action? onDispose) - { - _onDispose = onDispose; - } - - private void RunTimer(CancellationToken cancellationToken = default) - { - _mockTimeSystem.Thread.Sleep(_dueTime); - if (_dueTime.TotalMilliseconds < 0) - { - cancellationToken.WaitHandle.WaitOne(_dueTime); - } - - Thread.Yield(); - DateTime nextPlannedExecution = _mockTimeSystem.DateTime.UtcNow; - while (!cancellationToken.IsCancellationRequested) - { - nextPlannedExecution += _period; - Exception? exception = null; - try - { - _callback(_state); - } - catch (Exception swallowedException) - { - _exception = exception = swallowedException; - } - - _callbackHandler.InvokeTimerExecutedCallbacks( - new TimerExecution( - _mockTimeSystem.DateTime.UtcNow, - _executionCount, - this, - exception)); - _executionCount++; - if (_countdownEvent?.Signal() == true) - { - _continueEvent.Wait(cancellationToken); - _continueEvent.Reset(); - } - - if (_exception != null && !_timerStrategy.SwallowExceptions) - { - break; - } - - if (_period.TotalMilliseconds <= 0 || - cancellationToken.IsCancellationRequested) - { - return; - } - - TimeSpan delay = nextPlannedExecution - _mockTimeSystem.DateTime.UtcNow; - if (delay > TimeSpan.Zero) - { - _mockTimeSystem.Thread.Sleep(delay); - } - - Thread.Yield(); - } - } - - private void Start() - { - Stop(); - CancellationTokenSource runningCancellationTokenSource; - lock (_lock) - { - _cancellationTokenSource = new CancellationTokenSource(); - runningCancellationTokenSource = _cancellationTokenSource; - } - - CancellationToken token = runningCancellationTokenSource.Token; - ManualResetEventSlim startCreateTimerThreads = new(); - Thread t = new(() => - { - try - { - startCreateTimerThreads.Set(); - RunTimer(token); - } - catch (Exception ex) - { - _exception = ex; - } - finally - { - runningCancellationTokenSource.Dispose(); - lock (_lock) - { - if (_cancellationTokenSource == runningCancellationTokenSource) - { - _cancellationTokenSource.Dispose(); - _cancellationTokenSource = null; - } - } - } - }) - { - IsBackground = true - }; - t.Start(); - startCreateTimerThreads.Wait(token); - } - - private void Stop() - { - lock (_lock) - { - if (_cancellationTokenSource is { IsCancellationRequested: false }) - { - _cancellationTokenSource?.Cancel(); - } - } - } -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMode.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerMode.cs deleted file mode 100644 index 349d13bb8..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerMode.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// The timer mode. -/// -public enum TimerMode -{ - /// - /// Start the timer thread immediately. - /// - /// This is the normal behaviour of real s. - /// - StartImmediately = 1, - - /// - /// Wait execution of timers until a is called. - /// - /// This simplifies certain test cases. - /// - StartOnMockWait = 2, -} diff --git a/Source/Testably.Abstractions.Testing/TimeSystem/TimerStrategy.cs b/Source/Testably.Abstractions.Testing/TimeSystem/TimerStrategy.cs deleted file mode 100644 index 4af50d0c9..000000000 --- a/Source/Testably.Abstractions.Testing/TimeSystem/TimerStrategy.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Testably.Abstractions.Testing.TimeSystem; - -/// -/// The timer strategy. -/// -public class TimerStrategy : ITimerStrategy -{ - /// - /// The default time strategy uses . - /// - public static ITimerStrategy Default { get; } - = new TimerStrategy(TimerMode.StartImmediately); - - /// - public TimerMode Mode { get; } - - /// - public bool SwallowExceptions { get; } - - /// - /// Initializes a new instance of . - /// - /// The timer mode. - /// Flag, indicating if exceptions should be swallowed. - public TimerStrategy( - TimerMode mode = TimerMode.StartImmediately, - bool swallowExceptions = false) - { - Mode = mode; - SwallowExceptions = swallowExceptions; - } -} diff --git a/Source/Testably.Abstractions/RealTimeSystem.cs b/Source/Testably.Abstractions/RealTimeSystem.cs index f6f288986..c2b752574 100644 --- a/Source/Testably.Abstractions/RealTimeSystem.cs +++ b/Source/Testably.Abstractions/RealTimeSystem.cs @@ -23,9 +23,5 @@ public ITask Task public IThread Thread => new ThreadWrapper(this); - /// - public ITimerFactory Timer - => new TimerFactory(this); - #endregion } diff --git a/Source/Testably.Abstractions/TimeSystem/TimerFactory.cs b/Source/Testably.Abstractions/TimeSystem/TimerFactory.cs deleted file mode 100644 index 9f2708fa6..000000000 --- a/Source/Testably.Abstractions/TimeSystem/TimerFactory.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.IO; -using System.Threading; - -namespace Testably.Abstractions.TimeSystem; - -internal sealed class TimerFactory : ITimerFactory -{ - internal TimerFactory(RealTimeSystem timeSystem) - { - TimeSystem = timeSystem; - } - - /// - public ITimeSystem TimeSystem { get; } - -#if FEATURE_TIMER_COUNT - /// - public long ActiveCount => Timer.ActiveCount; -#endif - - /// - public ITimer New(TimerCallback callback) - => Wrap(new Timer(callback)); - - /// - public ITimer New(TimerCallback callback, object? state, int dueTime, int period) - => Wrap(new Timer(callback, state, dueTime, period)); - - /// - public ITimer New(TimerCallback callback, object? state, long dueTime, long period) - => Wrap(new Timer(callback, state, dueTime, period)); - - /// - public ITimer New(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period) - => Wrap(new Timer(callback, state, dueTime, period)); - - /// - public ITimer Wrap(Timer timer) - => new TimerWrapper(TimeSystem, timer); -} diff --git a/Source/Testably.Abstractions/TimeSystem/TimerWrapper.cs b/Source/Testably.Abstractions/TimeSystem/TimerWrapper.cs deleted file mode 100644 index fc2234e5c..000000000 --- a/Source/Testably.Abstractions/TimeSystem/TimerWrapper.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Testably.Abstractions.TimeSystem; - -internal sealed class TimerWrapper : ITimer -{ - private readonly Timer _timer; - - internal TimerWrapper(ITimeSystem timeSystem, Timer timer) - { - TimeSystem = timeSystem; - _timer = timer; - } - - #region ITimer Members - - /// - public ITimeSystem TimeSystem { get; } - - /// - public bool Change(int dueTime, int period) - => _timer.Change(dueTime, period); - - /// - public bool Change(long dueTime, long period) - => _timer.Change(dueTime, period); - - /// - public bool Change(TimeSpan dueTime, TimeSpan period) - => _timer.Change(dueTime, period); - - /// - public bool Dispose(WaitHandle notifyObject) - => _timer.Dispose(notifyObject); - - /// - public void Dispose() - => _timer.Dispose(); - -#if FEATURE_ASYNC_DISPOSABLE - /// - public ValueTask DisposeAsync() - => _timer.DisposeAsync(); -#endif - - #endregion -} diff --git a/Testably.Abstractions.v3.ncrunchsolution b/Testably.Abstractions.v3.ncrunchsolution deleted file mode 100644 index 420dc0202..000000000 --- a/Testably.Abstractions.v3.ncrunchsolution +++ /dev/null @@ -1,16 +0,0 @@ - - - True - - Source\Testably.Abstractions.Testing\Testably.Abstractions.Testing.csproj:netstandard2.1 - Source\Testably.Abstractions.Testing\Testably.Abstractions.Testing.csproj:netstandard2.0 - Source\Testably.Abstractions\Testably.Abstractions.csproj:netstandard2.1 - Source\Testably.Abstractions\Testably.Abstractions.csproj:netstandard2.0 - Tests\Testably.Abstractions.Tests\Testably.Abstractions.Tests.csproj - Source\Testably.Abstractions.Extensions\Testably.Abstractions.Extensions.csproj:netstandard2.0 - Source\Testably.Abstractions.Extensions\Testably.Abstractions.Extensions.csproj:netstandard2.1 - Tests\Testably.Abstractions.Extensions.Tests\Testably.Abstractions.Extensions.Tests.csproj - - True - - \ No newline at end of file diff --git a/Tests/Helpers/Testably.Abstractions.TestHelpers/Test.cs b/Tests/Helpers/Testably.Abstractions.TestHelpers/Test.cs index fe2548f71..33cf0a2ab 100644 --- a/Tests/Helpers/Testably.Abstractions.TestHelpers/Test.cs +++ b/Tests/Helpers/Testably.Abstractions.TestHelpers/Test.cs @@ -41,13 +41,6 @@ public static void SkipBrittleTestsOnRealFileSystem( "Brittle tests are skipped on the real file system."); } - public static void SkipBrittleTestsOnRealTimeSystem( - ITimeSystem timeSystem, bool condition = true) - { - Skip.If(timeSystem is RealTimeSystem && condition, - "Brittle tests are skipped on the real time system."); - } - public static void SkipIfLongRunningTestsShouldBeSkipped(IFileSystem fileSystem) { #if DEBUG && !INCLUDE_LONGRUNNING_TESTS_ALSO_IN_DEBUG_MODE diff --git a/Tests/Testably.Abstractions.Parity.Tests/ParityTests.cs b/Tests/Testably.Abstractions.Parity.Tests/ParityTests.cs index 3fc6c4f60..2cc08a268 100644 --- a/Tests/Testably.Abstractions.Parity.Tests/ParityTests.cs +++ b/Tests/Testably.Abstractions.Parity.Tests/ParityTests.cs @@ -136,18 +136,6 @@ public void IRandomAndIRandomFactory_EnsureParityWith_Random() parityErrors.Should().BeEmpty(); } - [Fact] - public void - ITimerAndITimerFactory_EnsureParityWith_Timer() - { - List parityErrors = Parity.Timer - .GetErrorsToInstanceType( - typeof(Timer), - _testOutputHelper); - - parityErrors.Should().BeEmpty(); - } - [Fact] public void IZipArchive_EnsureParityWith_ZipArchive() { diff --git a/Tests/Testably.Abstractions.Parity.Tests/TestHelpers/Parity.cs b/Tests/Testably.Abstractions.Parity.Tests/TestHelpers/Parity.cs index 5237a44df..014bd789e 100644 --- a/Tests/Testably.Abstractions.Parity.Tests/TestHelpers/Parity.cs +++ b/Tests/Testably.Abstractions.Parity.Tests/TestHelpers/Parity.cs @@ -2,7 +2,6 @@ using System.Collections.ObjectModel; using System.IO; using System.IO.Compression; -using System.Threading; namespace Testably.Abstractions.Parity.Tests.TestHelpers; @@ -63,25 +62,6 @@ public class Parity }); public ParityCheck Random { get; } = new(); - - public ParityCheck Timer { get; } = new(excludeMethods: new[] - { - typeof(Timer).GetMethod(nameof(System.Threading.Timer.Change), new[] - { - typeof(uint), - typeof(uint) - }) - }, excludeConstructors: new[] - { - typeof(Timer).GetConstructor(new[] - { - typeof(TimerCallback), - typeof(object), - typeof(uint), - typeof(uint) - }) - }); - public ParityCheck ZipArchive { get; } = new(); public ParityCheck ZipArchiveEntry { get; } = new(excludeMethods: new[] diff --git a/Tests/Testably.Abstractions.Testing.Tests/FileSystem/FileSystemWatcherMockTests.cs b/Tests/Testably.Abstractions.Testing.Tests/FileSystem/FileSystemWatcherMockTests.cs index a324513ed..ab61f07ff 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/FileSystem/FileSystemWatcherMockTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/FileSystem/FileSystemWatcherMockTests.cs @@ -1,7 +1,6 @@ using System.IO; using System.Threading; using Testably.Abstractions.Testing.FileSystemInitializer; -using Testably.Abstractions.Testing.Tests.TestHelpers; namespace Testably.Abstractions.Testing.Tests.FileSystem; @@ -38,8 +37,6 @@ public void Dispose() public void Error_DefaultTo64Messages_ShouldBeTriggeredWhenBufferOverflows( string path) { - Skip.If(Test.RunsOnWindows, "Brittle test under Windows on GitHub"); - FileSystem.Directory.CreateDirectory(path); IFileSystemWatcher fileSystemWatcher = FileSystem.FileSystemWatcher.New(BasePath); @@ -80,8 +77,6 @@ public void Error_DefaultTo64Messages_ShouldBeTriggeredWhenBufferOverflows( public void Error_ShouldBeTriggeredWhenBufferOverflows( int internalBufferSize, string path) { - Skip.If(Test.RunsOnWindows, "Brittle test under Windows on GitHub"); - int maxMessages = internalBufferSize / 128; FileSystem.Directory.CreateDirectory(path); IFileSystemWatcher fileSystemWatcher = @@ -112,7 +107,7 @@ public void Error_ShouldBeTriggeredWhenBufferOverflows( FileSystem.Directory.CreateDirectory($"{i}_{path}"); } - block2.Wait(10000).Should().BeTrue(); + block2.Wait(5000).Should().BeTrue(); fileSystemWatcher.Dispose(); result.Should().NotBeNull(); result!.GetException().Should().BeOfType(); diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/NotificationHandlerTests.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/NotificationHandlerTests.cs index 098a338b1..4e09b0b04 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/NotificationHandlerTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/NotificationHandlerTests.cs @@ -1,6 +1,5 @@ using System.Threading; using Testably.Abstractions.Testing.Tests.TestHelpers; -using Testably.Abstractions.Testing.TimeSystem; namespace Testably.Abstractions.Testing.Tests.TimeSystem; @@ -298,109 +297,4 @@ public void receivedTimeout.Should().Be(expectedTimeout); } - - [Fact] - public void - OnTimerExecuted_DisposedCallback_ShouldNotBeCalled() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedValue = null; - IDisposable disposable = timeSystem.On.TimerExecuted(d => receivedValue = d); - - disposable.Dispose(); - timeSystem.Timer.New(_ => { }, null, - TimeTestHelper.GetRandomInterval(), - TimeTestHelper.GetRandomInterval()); - - timerHandler[0].Wait(); - receivedValue.Should().BeNull(); - } - - [Fact] - public void - OnTimerExecuted_MultipleCallbacks_DisposeOne_ShouldCallOtherCallbacks() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedTimeout1 = null; - TimerExecution? receivedTimeout2 = null; - - using (timeSystem.On.TimerExecuted(d => receivedTimeout1 = d)) - { - timeSystem.On.TimerExecuted(d => receivedTimeout2 = d).Dispose(); - timeSystem.Timer.New(_ => { }, null, - TimeTestHelper.GetRandomInterval(), - TimeTestHelper.GetRandomInterval()); - timerHandler[0].Wait(); - } - - receivedTimeout1.Should().NotBeNull(); - receivedTimeout2.Should().BeNull(); - } - - [Fact] - public void - OnTimerExecuted_MultipleCallbacks_ShouldAllBeCalled() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedTimeout1 = null; - TimerExecution? receivedTimeout2 = null; - - using (timeSystem.On.TimerExecuted(d => receivedTimeout1 = d)) - { - using (timeSystem.On.TimerExecuted(d => receivedTimeout2 = d)) - { - timeSystem.Timer.New(_ => { }, null, - TimeTestHelper.GetRandomInterval(), - TimeTestHelper.GetRandomInterval()); - timerHandler[0].Wait(); - } - } - - receivedTimeout1.Should().NotBeNull(); - receivedTimeout2.Should().NotBeNull(); - } - - [Fact] - public void - OnTimerExecuted_WithMilliseconds_ShouldExecuteCallbackWithCorrectParameter() - { - int millisecondsTimeout = new Random().Next(); - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedValue = null; - DateTime now = timeSystem.DateTime.UtcNow; - - using (timeSystem.On.TimerExecuted(d => receivedValue = d)) - { - timeSystem.Timer.New(_ => { }, null, millisecondsTimeout, 0); - timerHandler[0].Wait(); - } - - TimeSpan difference = receivedValue!.Time - now; - difference.Should().Be(TimeSpan.FromMilliseconds(millisecondsTimeout)); - } - - [Fact] - public void - OnTimerExecuted_WithTimeSpan_ShouldExecuteCallbackWithCorrectParameter() - { - TimeSpan expectedTimeout = TimeTestHelper.GetRandomInterval(); - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedValue = null; - DateTime now = timeSystem.DateTime.UtcNow; - - using (timeSystem.On.TimerExecuted(d => receivedValue = d)) - { - timeSystem.Timer.New(_ => { }, null, expectedTimeout, TimeSpan.Zero); - timerHandler[0].Wait(); - } - - TimeSpan difference = receivedValue!.Time - now; - difference.Should().Be(expectedTimeout); - } } diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimeSystemExtensibilityTests.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimeSystemExtensibilityTests.cs index fac432cd9..fcac27bd4 100644 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimeSystemExtensibilityTests.cs +++ b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimeSystemExtensibilityTests.cs @@ -31,15 +31,6 @@ public void Thread_ShouldSetExtensionPoint(ITimeSystem timeSystem) result.Should().Be(timeSystem); } - [SkippableTheory] - [MemberData(nameof(GetTimeSystems))] - public void Timer_ShouldSetExtensionPoint(ITimeSystem timeSystem) - { - ITimeSystem result = timeSystem.Timer.TimeSystem; - - result.Should().Be(timeSystem); - } - public static IEnumerable GetTimeSystems => new List { diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerFactoryMockTests.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerFactoryMockTests.cs deleted file mode 100644 index 3e8e817f3..000000000 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerFactoryMockTests.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Threading; - -namespace Testably.Abstractions.Testing.Tests.TimeSystem; - -public class TimerFactoryMockTests -{ - [Fact] - public void Wrap_ShouldThrowNotSupportedException() - { - MockTimeSystem timeSystem = new(); - - Exception? exception = Record.Exception(() => - { - timeSystem.Timer.Wrap(new Timer(_ => { })); - }); - - exception.Should().BeOfType(); - } -} diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerHandlerTest.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerHandlerTest.cs deleted file mode 100644 index b556d17d8..000000000 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerHandlerTest.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections.Generic; -using Testably.Abstractions.Testing.TimeSystem; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Testing.Tests.TimeSystem; - -public class TimerHandlerTest -{ - [Fact] - public void Index_MultipleTimers_ShouldIncrement() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler sut = timeSystem.TimerHandler; - - using ITimer timer0 = timeSystem.Timer.New(_ => { }, null, 0, 100); - using ITimer timer1 = timeSystem.Timer.New(_ => { }, null, 0, 100); - - sut[0].Should().Be(timer0); - sut[1].Should().Be(timer1); - } - - [Fact] - public void Index_ShouldNotReuseDisposedIndexes() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler sut = timeSystem.TimerHandler; - - ITimer timer0 = timeSystem.Timer.New(_ => { }, null, 0, 100); - using ITimer timer1 = timeSystem.Timer.New(_ => { }, null, 0, 100); - timer0.Dispose(); - using ITimer timer2 = timeSystem.Timer.New(_ => { }, null, 0, 100); - - sut[1].Should().Be(timer1); - sut[2].Should().Be(timer2); - } - - [Fact] - public void Index_AccessDisposedIndex_ShouldThrowException() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler sut = timeSystem.TimerHandler; - - ITimer timer0 = timeSystem.Timer.New(_ => { }, null, 0, 100); - timer0.Dispose(); - - Exception? exception = Record.Exception(() => - { - _ = sut[0]; - }); - - exception.Should().BeOfType(); - } -} diff --git a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs b/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs deleted file mode 100644 index e0c9ce17d..000000000 --- a/Tests/Testably.Abstractions.Testing.Tests/TimeSystem/TimerMockTests.cs +++ /dev/null @@ -1,374 +0,0 @@ -using System.Collections.Concurrent; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Testably.Abstractions.Testing.FileSystemInitializer; -using Testably.Abstractions.Testing.Tests.TestHelpers; -using Testably.Abstractions.Testing.TimeSystem; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Testing.Tests.TimeSystem; - -public class TimerMockTests -{ - [SkippableTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(2000)] - public void Change_ValidDueTimeValue_ShouldNotThrowException(int dueTime) - { - MockTimeSystem timeSystem = new MockTimeSystem(); - using ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(dueTime, 0); - }); - - exception.Should().BeNull(); - } - - [SkippableTheory] - [InlineData(-1)] - [InlineData(0)] - [InlineData(2000)] - public void Change_ValidPeriodValue_ShouldNotThrowException(int period) - { - MockTimeSystem timeSystem = new MockTimeSystem(); - using ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0, period); - }); - - exception.Should().BeNull(); - } - - [Fact] - public void Dispose_ShouldDisposeTimer() - { - MockTimeSystem timeSystem = new(); - ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 100, 200); - timer.Dispose(); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0, 0); - }); - - exception.Should().BeOfType(); - } - -#if FEATURE_ASYNC_DISPOSABLE - [Fact] - public async Task DisposeAsync_ShouldDisposeTimer() - { - MockTimeSystem timeSystem = new(); - ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 100, 200); - await timer.DisposeAsync(); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0, 0); - }); - - exception.Should().BeOfType(); - } -#endif - - [Fact] - public void Dispose_WithUnknownWaitHandle_ShouldThrowNotSupportedException() - { - MockTimeSystem timeSystem = new(); - ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 100, 200); - using DummyWaitHandle waitHandle = new(); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Dispose(waitHandle); - }); - - exception.Should().BeOfType(); - } - - [Fact] - public void Exception_ShouldBeIncludedInTimerExecutedNotification() - { - TestingException exception = new("foo"); - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(swallowExceptions: true)); - ITimerHandler timerHandler = timeSystem.TimerHandler; - TimerExecution? receivedTimeout = null; - - using (timeSystem.On.TimerExecuted(d => receivedTimeout = d)) - { - timeSystem.Timer.New(_ => throw exception, null, - TimeTestHelper.GetRandomInterval(), - TimeTestHelper.GetRandomInterval()); - try - { - timerHandler[0].Wait(); - } - catch (TestingException) - { - // Expect a TestingException to be thrown - } - } - - receivedTimeout!.Exception.Should().Be(exception); - } - - [Fact] - public void Exception_WhenSwallowExceptionsIsSet_ShouldContinueTimerExecution() - { - MockTimeSystem timeSystem = new(); - timeSystem.WithTimerStrategy( - new TimerStrategy(swallowExceptions: true)); - Exception exception = new("foo"); - int count = 0; - ManualResetEventSlim ms = new(); - using ITimer timer = timeSystem.Timer.New(_ => - { - if (count++ == 1) - { - throw exception; - } - - if (count == 3) - { - ms.Set(); - } - }, null, 0, 20); - - ms.Wait(10000).Should().BeTrue(); - - count.Should().BeGreaterThanOrEqualTo(3); - } - - [Fact] - public void Exception_WhenSwallowExceptionsIsNotSet_ShouldThrowExceptionOnWait() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(swallowExceptions: false)); - Exception expectedException = new("foo"); - using ITimer timer = timeSystem.Timer.New( - _ => throw expectedException, null, 0, 20); - - Exception? exception = Record.Exception(() => - { - timeSystem.TimerHandler[0].Wait(); - }); - - exception.Should().Be(expectedException); - } - - [Fact] - public void Exception_WhenSwallowExceptionsIsNotSet_ShouldStopTimer() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(swallowExceptions: false)); - Exception expectedException = new("foo"); - int count = 0; - using ITimer timer = timeSystem.Timer.New( - _ => - { - if (++count == 1) - { - throw expectedException; - } - }, null, 0, 20); - - Exception? exception = Record.Exception(() => - { - Thread.Sleep(10); - timeSystem.TimerHandler[0].Wait(); - }); - - exception.Should().Be(expectedException); - count.Should().Be(1); - } - - [Fact] - public void Exception_WhenSwallowExceptionsIsSet_ShouldContinueTimer() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(swallowExceptions: true)); - Exception expectedException = new("foo"); - int count = 0; - using ITimer timer = timeSystem.Timer.New( - _ => - { - if (++count == 1) - { - throw expectedException; - } - }, null, 0, 20); - - Exception? exception = Record.Exception(() => - { - Thread.Sleep(10); - timeSystem.TimerHandler[0].Wait(); - }); - - exception.Should().Be(expectedException); - count.Should().BeGreaterThan(1); - } - - [Fact] - public void ExecutionCount_ShouldBeIncrementedAndZeroBased() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - ConcurrentBag executionCounter = new(); - - using (timeSystem.On.TimerExecuted(d => executionCounter.Add(d.ExecutionCount))) - { - timeSystem.Timer.New(_ => { }, null, - TimeTestHelper.GetRandomInterval(), - TimeTestHelper.GetRandomInterval()); - - timerHandler[0].Wait(10); - } - - executionCounter.OrderBy(x => x).Should() - .BeEquivalentTo(Enumerable.Range(0, executionCounter.Count)); - } - - [Fact] - public void New_WithStartOnMockWaitMode_ShouldOnlyStartWhenCallingWait() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler timerHandler = timeSystem.TimerHandler; - - int count = 0; - using ITimer timer = timeSystem.Timer.New(_ => count++, null, 0, 100); - - Thread.Sleep(10); - count.Should().Be(0); - timerHandler[0].Wait(); - count.Should().BeGreaterThan(0); - } - - [Fact] - public void Wait_InvalidExecutionCount_ShouldThrowArgumentOutOfRangeException() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - - using ITimer timer = timeSystem.Timer.New(_ => { }, null, 0, 100); - - Exception? exception = Record.Exception(() => - { - timerHandler[0].Wait(0); - }); - - exception.Should().BeOfType() - .Which.ParamName.Should().Be("executionCount"); - } - - [SkippableFact] - public void Wait_Infinite_ShouldBeValidTimeout() - { - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler timerHandler = timeSystem.TimerHandler; - - using ITimer timer = timeSystem.Timer.New(_ => - { - }, null, 0, 100); - - Exception? exception = Record.Exception(() => - { - timerHandler[0].Wait(timeout: Timeout.Infinite); - }); - - exception.Should().BeNull(); - } - - [Fact] - public void Wait_InvalidTimeout_ShouldThrowArgumentOutOfRangeException() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - - using ITimer timer = timeSystem.Timer.New(_ => { }, null, 0, 100); - - Exception? exception = Record.Exception(() => - { - timerHandler[0].Wait(timeout: -2); - }); - - exception.Should().BeOfType() - .Which.ParamName.Should().Be("timeout"); - } - - [Fact] - public void Wait_TimeoutExpired_ShouldThrowTimeoutException() - { - MockTimeSystem timeSystem = new(); - ITimerHandler timerHandler = timeSystem.TimerHandler; - ManualResetEventSlim ms = new(); - - int count = 0; - using ITimer timer = timeSystem.Timer.New(_ => - { - count++; - ms.Wait(); - }, null, 0, 100); - - Exception? exception = Record.Exception(() => - { - timerHandler[0].Wait(10, 300); - }); - ms.Set(); - - exception.Should().BeOfType(); - count.Should().BeGreaterThan(0); - } - - [SkippableFact] - public void Wait_WithExecutionCount_ShouldWaitForSpecifiedNumberOfExecutions() - { - Skip.If(Test.RunsOnWindows, "Brittle test under Windows on GitHub"); - - int executionCount = 10; - MockTimeSystem timeSystem = new MockTimeSystem() - .WithTimerStrategy(new TimerStrategy(TimerMode.StartOnMockWait)); - ITimerHandler timerHandler = timeSystem.TimerHandler; - - int count = 0; - using ITimer timer = timeSystem.Timer.New(_ => - { - count++; - }, null, 0, 100); - - count.Should().Be(0); - timerHandler[0].Wait(executionCount, callback: t => - { - t.Dispose(); - }); - Thread.Sleep(100); - count.Should().Be(executionCount); - } - - private class DummyWaitHandle : WaitHandle - { - } -} diff --git a/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/FilterTests.cs b/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/FilterTests.cs index ebcdf3e59..c255e21fd 100644 --- a/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/FilterTests.cs +++ b/Tests/Testably.Abstractions.Tests/FileSystem/FileSystemWatcher/FilterTests.cs @@ -68,8 +68,6 @@ public void Filter_NotMatching_ShouldNotTriggerNotification( public void Filters_ShouldMatchAnyOfTheSpecifiedFilters( string[] filteredPaths, string[] otherPaths) { - Test.SkipBrittleTestsOnRealFileSystem(FileSystem); - foreach (string path in otherPaths.Concat(filteredPaths)) { FileSystem.Directory.CreateDirectory(path); diff --git a/Tests/Testably.Abstractions.Tests/TestHelpers/ThreadTestHelpers.cs b/Tests/Testably.Abstractions.Tests/TestHelpers/ThreadTestHelpers.cs deleted file mode 100644 index 3ada4bfa6..000000000 --- a/Tests/Testably.Abstractions.Tests/TestHelpers/ThreadTestHelpers.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Threading; - -namespace Testably.Abstractions.Tests.TestHelpers; - -public static class ThreadTestHelpers -{ - /// - /// - /// - public static Thread CreateGuardedThread(out Action waitForThread, Action start) - { - Exception? backgroundEx = null; - Thread t = - new(() => - { - try - { - start(); - } - catch (Exception ex) - { - backgroundEx = ex; - } - }); - - void LocalCheckForThreadErrors() - { - if (backgroundEx != null) - { - throw new AggregateException(backgroundEx); - } - } - - waitForThread = - () => - { - Assert.True(t.Join(60000)); - LocalCheckForThreadErrors(); - }; - return t; - } -} diff --git a/Tests/Testably.Abstractions.Tests/TimeSystem/TimerFactoryTests.cs b/Tests/Testably.Abstractions.Tests/TimeSystem/TimerFactoryTests.cs deleted file mode 100644 index 39a26bc90..000000000 --- a/Tests/Testably.Abstractions.Tests/TimeSystem/TimerFactoryTests.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Tests.TimeSystem; - -// ReSharper disable once PartialTypeWithSinglePart -public abstract partial class TimerFactoryTests - : TimeSystemTestBase - where TTimeSystem : ITimeSystem -{ -#if FEATURE_TIMER_COUNT - [SkippableFact] - public void ActiveCount_ShouldBeIncrementedWhenCreatingANewTimer() - { - using ITimer timer = TimeSystem.Timer.New(_ => { }); - TimeSystem.Timer.ActiveCount.Should().BeGreaterThan(0); - } - - [SkippableFact] - public void ActiveCount_ShouldBeResetWhenDisposingATimer() - { - const int timersPerThread = 64; - int processorCount = Environment.ProcessorCount; - int totalTimerCount = processorCount * timersPerThread; - - List? timers = new(totalTimerCount); - - void TimerCallback(object? _) - { - } - - ManualResetEvent? startCreateTimerThreads = new(false); - - void CreateTimerThreadStart() - { - startCreateTimerThreads.WaitOne(); - for (int i = 0; i < timersPerThread; ++i) - { - lock (timers) - { - timers.Add(TimeSystem.Timer.New(TimerCallback, null, 60000, 60000)); - Assert.True(TimeSystem.Timer.ActiveCount >= timers.Count); - } - } - } - - Action[] waitsForThread = new Action[processorCount]; - for (int i = 0; i < processorCount; ++i) - { - Thread t = - ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], - CreateTimerThreadStart); - t.IsBackground = true; - t.Start(); - } - - startCreateTimerThreads.Set(); - foreach (Action waitForThread in waitsForThread) - { - waitForThread(); - } - - while (timers.Count > 0) - { - long timerCountBeforeRemove = TimeSystem.Timer.ActiveCount; - int endIndex = timers.Count - (processorCount * 8); - for (int i = timers.Count - 1; i >= Math.Max(0, endIndex); --i) - { - timers[i].Dispose(); - timers.RemoveAt(i); - } - - if (endIndex >= 0) - { - Assert.True(TimeSystem.Timer.ActiveCount < timerCountBeforeRemove); - } - } - } -#endif - - [SkippableTheory] - [InlineData(-2)] - [InlineData(-500)] - public void New_InvalidDueTime_ShouldThrowArgumentOutOfRangeException(int dueTime) - { - Exception? exception = Record.Exception(() => - { - TimeSystem.Timer.New(_ => - { - }, null, dueTime, 0); - }); - - exception.Should() - .BeException(hResult: -2146233086, paramName: nameof(dueTime)); - } - - [SkippableTheory] - [InlineData(-2)] - [InlineData(-500)] - public void New_InvalidPeriod_ShouldThrowArgumentOutOfRangeException(int period) - { - Exception? exception = Record.Exception(() => - { - TimeSystem.Timer.New(_ => - { - }, null, 0, period); - }); - - exception.Should() - .BeException(hResult: -2146233086, paramName: nameof(period)); - } - - [SkippableFact] - public void New_WithPeriod_ShouldStartTimer() - { - int count = 0; - ManualResetEventSlim ms = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - count++; - if (count > 1) - { - ms.Set(); - } - }, null, 0, 50); - - ms.Wait(500).Should().BeTrue(); - count.Should().BeGreaterOrEqualTo(2); - } - - [SkippableFact] - public void New_WithDueTime_ShouldStartTimerOnce() - { - int count = 0; - ManualResetEventSlim ms = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - count++; - if (count > 1) - { - ms.Set(); - } - }, null, 50, 0); - - ms.Wait(500).Should().BeFalse(); - count.Should().BeGreaterOrEqualTo(1); - } - - [SkippableFact] - public void New_WithoutPeriod_ShouldNotStartTimer() - { - int count = 0; - ManualResetEventSlim ms = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - count++; - if (count > 1) - { - ms.Set(); - } - }); - - ms.Wait(500).Should().BeFalse(); - count.Should().Be(0); - } -} diff --git a/Tests/Testably.Abstractions.Tests/TimeSystem/TimerTests.cs b/Tests/Testably.Abstractions.Tests/TimeSystem/TimerTests.cs deleted file mode 100644 index f60f8e024..000000000 --- a/Tests/Testably.Abstractions.Tests/TimeSystem/TimerTests.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using Testably.Abstractions.TimeSystem; - -namespace Testably.Abstractions.Tests.TimeSystem; - -// ReSharper disable once PartialTypeWithSinglePart -public abstract partial class TimerTests - : TimeSystemTestBase - where TTimeSystem : ITimeSystem -{ - private const int TimerMultiplier = 10; - - [SkippableFact] - public void Change_DisposedTimer_ShouldThrowObjectDisposedException() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 0, 200); - timer.Dispose(); - - Exception? exception = Record.Exception(() => - { - timer.Change(100, 200); - }); - - exception.Should().BeOfType(); - } - - [SkippableFact] - public void Change_Infinite_ShouldBeValidDueTime() - { - using ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(Timeout.Infinite, 0); - }); - - exception.Should().BeNull(); - } - - [SkippableFact] - public void Change_Infinite_ShouldBeValidPeriod() - { - using ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0, Timeout.Infinite); - }); - - exception.Should().BeNull(); - } - - [SkippableTheory] - [InlineData(-2)] - [InlineData(-500)] - public void Change_InvalidDueTime_ShouldThrowArgumentOutOfRangeException(int dueTime) - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - timer.Change(dueTime, 0); - }); - - exception.Should() - .BeException(hResult: -2146233086, - paramName: nameof(dueTime)); - } - - [SkippableTheory] - [InlineData(-2)] - [InlineData(-500)] - public void Change_InvalidPeriod_ShouldThrowArgumentOutOfRangeException(int period) - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - - Exception? exception = Record.Exception(() => - { - timer.Change(0, period); - }); - - exception.Should() - .BeException(hResult: -2146233086, - paramName: nameof(period)); - } - - [SkippableFact] - public void Change_SameValues_ShouldReturnTrue() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - - bool result = timer.Change(100, 200); - - result.Should().BeTrue(); - } - - [SkippableFact] - public void Change_WithInt_ShouldResetTimer() - { - Test.SkipBrittleTestsOnRealTimeSystem(TimeSystem); - - List triggerTimes = new(); - DateTime previousTime = TimeSystem.DateTime.Now; - ManualResetEventSlim ms = new(); - ManualResetEventSlim ms2 = new(); - ManualResetEventSlim ms3 = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - DateTime now = TimeSystem.DateTime.Now; - double diff = (now - previousTime).TotalMilliseconds; - previousTime = now; - ms.Set(); - triggerTimes.Add((int)diff); - ms2.Wait(); - if (triggerTimes.Count > 3) - { - ms3.Set(); - } - }, null, 0 * TimerMultiplier, 200 * TimerMultiplier); - ms.Wait(); - using ITimer timer2 = TimeSystem.Timer.New(_ => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0 * TimerMultiplier, 200 * TimerMultiplier); - ms2.Set(); - }, null, 100 * TimerMultiplier, 0 * TimerMultiplier); - - ms3.Wait(10000 * TimerMultiplier); - - triggerTimes[0].Should() - .BeLessThan(30 * TimerMultiplier); - triggerTimes[1].Should() - .BeGreaterThan(70 * TimerMultiplier).And - .BeLessThan(130 * TimerMultiplier); - for (int i = 2; i < triggerTimes.Count; i++) - { - triggerTimes[i].Should() - .BeGreaterThan(170 * TimerMultiplier).And - .BeLessThan(230 * TimerMultiplier); - } - } - - [SkippableFact] - public void Change_WithLong_ShouldResetTimer() - { - Test.SkipBrittleTestsOnRealTimeSystem(TimeSystem); - - List triggerTimes = new(); - DateTime previousTime = TimeSystem.DateTime.Now; - ManualResetEventSlim ms = new(); - ManualResetEventSlim ms2 = new(); - ManualResetEventSlim ms3 = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - DateTime now = TimeSystem.DateTime.Now; - double diff = (now - previousTime).TotalMilliseconds; - previousTime = now; - ms.Set(); - triggerTimes.Add((int)diff); - ms2.Wait(); - if (triggerTimes.Count > 3) - { - ms3.Set(); - } - }, null, 0L * TimerMultiplier, 200L * TimerMultiplier); - ms.Wait(); - using ITimer timer2 = TimeSystem.Timer.New(_ => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(0L * TimerMultiplier, 200L * TimerMultiplier); - ms2.Set(); - }, null, 100L * TimerMultiplier, 0L * TimerMultiplier); - - ms3.Wait(10000); - - triggerTimes[0].Should() - .BeLessThan(30 * TimerMultiplier); - triggerTimes[1].Should() - .BeGreaterThan(70 * TimerMultiplier).And - .BeLessThan(130 * TimerMultiplier); - for (int i = 2; i < triggerTimes.Count; i++) - { - triggerTimes[i].Should() - .BeGreaterThan(170 * TimerMultiplier).And - .BeLessThan(230 * TimerMultiplier); - } - } - - [SkippableFact] - public void Change_WithTimeSpan_ShouldResetTimer() - { - Test.SkipBrittleTestsOnRealTimeSystem(TimeSystem); - - List triggerTimes = new(); - DateTime previousTime = TimeSystem.DateTime.Now; - ManualResetEventSlim ms = new(); - ManualResetEventSlim ms2 = new(); - ManualResetEventSlim ms3 = new(); - using ITimer timer = TimeSystem.Timer.New(_ => - { - DateTime now = TimeSystem.DateTime.Now; - double diff = (now - previousTime).TotalMilliseconds; - previousTime = now; - ms.Set(); - triggerTimes.Add((int)diff); - ms2.Wait(); - if (triggerTimes.Count > 3) - { - ms3.Set(); - } - }, null, TimeSpan.FromMilliseconds(0 * TimerMultiplier), - TimeSpan.FromMilliseconds(200 * TimerMultiplier)); - ms.Wait(); - using ITimer timer2 = TimeSystem.Timer.New(_ => - { - // ReSharper disable once AccessToDisposedClosure - timer.Change(TimeSpan.FromMilliseconds(0 * TimerMultiplier), - TimeSpan.FromMilliseconds(200 * TimerMultiplier)); - ms2.Set(); - }, null, TimeSpan.FromMilliseconds(100 * TimerMultiplier), - TimeSpan.FromMilliseconds(0 * TimerMultiplier)); - - ms3.Wait(10000); - - triggerTimes[0].Should() - .BeLessThan(30 * TimerMultiplier); - triggerTimes[1].Should() - .BeGreaterThan(70 * TimerMultiplier).And - .BeLessThan(130 * TimerMultiplier); - for (int i = 2; i < triggerTimes.Count; i++) - { - triggerTimes[i].Should() - .BeGreaterThan(170 * TimerMultiplier).And - .BeLessThan(230 * TimerMultiplier); - } - } - - [SkippableFact] - public void Dispose_WithManualResetEventWaitHandle_ShouldBeSet() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - using ManualResetEvent waitHandle = new(false); - bool result = timer.Dispose(waitHandle); - - waitHandle.WaitOne(1000).Should().BeTrue(); - result.Should().BeTrue(); - Record.Exception(() => timer.Change(0, 0)) - .Should().BeOfType(); - } - - [SkippableFact] - public void Dispose_WithMutexWaitHandle_ShouldBeSet() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - using Mutex waitHandle = new(false); - bool result = timer.Dispose(waitHandle); - - waitHandle.WaitOne(1000).Should().BeTrue(); - result.Should().BeTrue(); - Record.Exception(() => timer.Change(0,0)) - .Should().BeOfType(); - } - - [SkippableFact] - public void Dispose_WithSemaphoreWaitHandle_ShouldBeSet() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - using Semaphore waitHandle = new(1, 1); - bool result = timer.Dispose(waitHandle); - - waitHandle.WaitOne(1000).Should().BeTrue(); - result.Should().BeTrue(); - Record.Exception(() => timer.Change(0, 0)) - .Should().BeOfType(); - } - - [SkippableFact] - public void Dispose_WithWaitHandleCalledTwice_ShouldReturnFalse() - { - ITimer timer = TimeSystem.Timer.New(_ => - { - }, null, 100, 200); - using ManualResetEvent waitHandle = new(false); - timer.Dispose(waitHandle); - - bool result = timer.Dispose(waitHandle); - - result.Should().BeFalse(); - } -}