Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Feature.Flags.props
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<DefineConstants Condition="'$(IS_NET8_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_RANDOM_ITEMS</DefineConstants>
<DefineConstants Condition="'$(IS_NET8_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_COMPRESSION_STREAM</DefineConstants>
<DefineConstants Condition="'$(IS_NET8_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_STOPWATCH_GETELAPSEDTIME</DefineConstants>
<DefineConstants Condition="'$(IS_NET8_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_PERIODIC_TIMER</DefineConstants>
<DefineConstants Condition="'$(IS_NET9_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_PATH_SPAN</DefineConstants>
<DefineConstants Condition="'$(IS_NET9_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_FILE_SPAN</DefineConstants>
<DefineConstants Condition="'$(IS_NET9_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_GUID_V7</DefineConstants>
Expand Down
2 changes: 1 addition & 1 deletion Pipeline/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ partial class Build : NukeBuild
/// <para />
/// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag.
/// </summary>
readonly BuildScope BuildScope = BuildScope.Default;
readonly BuildScope BuildScope = BuildScope.CoreOnly;

[Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
Expand Down
7 changes: 7 additions & 0 deletions Source/Testably.Abstractions.Interface/ITimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ public interface ITimeSystem
/// </summary>
IDateTime DateTime { get; }

#if FEATURE_PERIODIC_TIMER
/// <summary>
/// Abstractions for <see cref="System.Threading.PeriodicTimer" />.
/// </summary>
IPeriodicTimerFactory PeriodicTimer { get; }
#endif

/// <summary>
/// Abstractions for <see cref="System.Diagnostics.Stopwatch" />.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#if FEATURE_PERIODIC_TIMER
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Testably.Abstractions.TimeSystem;

/// <summary>
/// Abstractions for <see cref="PeriodicTimer" />.
/// </summary>
public interface IPeriodicTimer : ITimeSystemEntity, IDisposable
{
/// <inheritdoc cref="PeriodicTimer.Period" />
TimeSpan Period { get; set; }

/// <inheritdoc cref="PeriodicTimer.WaitForNextTickAsync(CancellationToken)" />
ValueTask<bool> WaitForNextTickAsync(CancellationToken cancellationToken = default);
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#if FEATURE_PERIODIC_TIMER
using System;
using System.Threading;

namespace Testably.Abstractions.TimeSystem;

/// <summary>
/// Factory for abstracting creation of <see cref="PeriodicTimer" />.
/// </summary>
public interface IPeriodicTimerFactory : ITimeSystemEntity
{
/// <inheritdoc cref="PeriodicTimer(TimeSpan)" />
IPeriodicTimer New(TimeSpan period);

/// <summary>
/// Wraps the <paramref name="timer" /> to the testable <see cref="IPeriodicTimer" />.
/// </summary>
IPeriodicTimer Wrap(PeriodicTimer timer);
}
#endif
8 changes: 8 additions & 0 deletions Source/Testably.Abstractions/RealTimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public sealed class RealTimeSystem : ITimeSystem
public RealTimeSystem()
{
DateTime = new DateTimeWrapper(this);
#if FEATURE_PERIODIC_TIMER
PeriodicTimer = new PeriodicTimerFactory(this);
#endif
Stopwatch = new StopwatchFactory(this);
Task = new TaskWrapper(this);
Thread = new ThreadWrapper(this);
Expand All @@ -27,6 +30,11 @@ public RealTimeSystem()
/// <inheritdoc cref="ITimeSystem.DateTime" />
public IDateTime DateTime { get; }

#if FEATURE_PERIODIC_TIMER
/// <inheritdoc cref="ITimeSystem.PeriodicTimer" />
public IPeriodicTimerFactory PeriodicTimer { get; }
#endif

/// <inheritdoc cref="ITimeSystem.Stopwatch" />
public IStopwatchFactory Stopwatch { get; }

Expand Down
29 changes: 29 additions & 0 deletions Source/Testably.Abstractions/TimeSystem/PeriodicTimerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#if FEATURE_PERIODIC_TIMER
using System;
using System.Threading;

namespace Testably.Abstractions.TimeSystem;

internal sealed class PeriodicTimerFactory : IPeriodicTimerFactory
{
internal PeriodicTimerFactory(RealTimeSystem timeSystem)
{
TimeSystem = timeSystem;
}

#region IPeriodicTimerFactory Members

/// <inheritdoc cref="ITimeSystemEntity.TimeSystem" />
public ITimeSystem TimeSystem { get; }

/// <inheritdoc cref="IPeriodicTimerFactory.New(TimeSpan)" />
public IPeriodicTimer New(TimeSpan period)
=> Wrap(new PeriodicTimer(period));

/// <inheritdoc cref="IPeriodicTimerFactory.Wrap(PeriodicTimer)" />
public IPeriodicTimer Wrap(PeriodicTimer timer)
=> new PeriodicTimerWrapper(TimeSystem, timer);

#endregion
}
#endif
40 changes: 40 additions & 0 deletions Source/Testably.Abstractions/TimeSystem/PeriodicTimerWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#if FEATURE_PERIODIC_TIMER
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Testably.Abstractions.TimeSystem;

internal sealed class PeriodicTimerWrapper : IPeriodicTimer
{
private readonly PeriodicTimer _periodicTimer;

internal PeriodicTimerWrapper(ITimeSystem timeSystem, PeriodicTimer periodicTimer)
{
TimeSystem = timeSystem;
_periodicTimer = periodicTimer;
}

#region IPeriodicTimer Members

/// <inheritdoc cref="IPeriodicTimer.Period" />
public TimeSpan Period
{
get => _periodicTimer.Period;
set => _periodicTimer.Period = value;
}

/// <inheritdoc cref="ITimeSystemEntity.TimeSystem" />
public ITimeSystem TimeSystem { get; }

/// <inheritdoc cref="IDisposable.Dispose()" />
public void Dispose()
=> _periodicTimer.Dispose();

/// <inheritdoc cref="IPeriodicTimer.WaitForNextTickAsync(CancellationToken)" />
public ValueTask<bool> WaitForNextTickAsync(CancellationToken cancellationToken = default)
=> _periodicTimer.WaitForNextTickAsync(cancellationToken);

#endregion
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace Testably.Abstractions
{
public RealTimeSystem() { }
public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
public Testably.Abstractions.TimeSystem.ITask Task { get; }
public Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace Testably.Abstractions
{
public RealTimeSystem() { }
public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
public Testably.Abstractions.TimeSystem.ITask Task { get; }
public Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace Testably.Abstractions
{
public RealTimeSystem() { }
public Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
public Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
public Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
public Testably.Abstractions.TimeSystem.ITask Task { get; }
public Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ namespace Testably.Abstractions
public interface ITimeSystem
{
Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
Testably.Abstractions.TimeSystem.ITask Task { get; }
Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down Expand Up @@ -141,6 +142,16 @@ namespace Testably.Abstractions.TimeSystem
System.DateTime UnixEpoch { get; }
System.DateTime UtcNow { get; }
}
public interface IPeriodicTimer : System.IDisposable, Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Period { get; set; }
System.Threading.Tasks.ValueTask<bool> WaitForNextTickAsync(System.Threading.CancellationToken cancellationToken = default);
}
public interface IPeriodicTimerFactory : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
Testably.Abstractions.TimeSystem.IPeriodicTimer New(System.TimeSpan period);
Testably.Abstractions.TimeSystem.IPeriodicTimer Wrap(System.Threading.PeriodicTimer timer);
}
public interface IStopwatch : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Elapsed { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ namespace Testably.Abstractions
public interface ITimeSystem
{
Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
Testably.Abstractions.TimeSystem.ITask Task { get; }
Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down Expand Up @@ -123,6 +124,16 @@ namespace Testably.Abstractions.TimeSystem
System.DateTime UnixEpoch { get; }
System.DateTime UtcNow { get; }
}
public interface IPeriodicTimer : System.IDisposable, Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Period { get; set; }
System.Threading.Tasks.ValueTask<bool> WaitForNextTickAsync(System.Threading.CancellationToken cancellationToken = default);
}
public interface IPeriodicTimerFactory : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
Testably.Abstractions.TimeSystem.IPeriodicTimer New(System.TimeSpan period);
Testably.Abstractions.TimeSystem.IPeriodicTimer Wrap(System.Threading.PeriodicTimer timer);
}
public interface IStopwatch : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Elapsed { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace Testably.Abstractions
public interface ITimeSystem
{
Testably.Abstractions.TimeSystem.IDateTime DateTime { get; }
Testably.Abstractions.TimeSystem.IPeriodicTimerFactory PeriodicTimer { get; }
Testably.Abstractions.TimeSystem.IStopwatchFactory Stopwatch { get; }
Testably.Abstractions.TimeSystem.ITask Task { get; }
Testably.Abstractions.TimeSystem.IThread Thread { get; }
Expand Down Expand Up @@ -127,6 +128,16 @@ namespace Testably.Abstractions.TimeSystem
System.DateTime UnixEpoch { get; }
System.DateTime UtcNow { get; }
}
public interface IPeriodicTimer : System.IDisposable, Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Period { get; set; }
System.Threading.Tasks.ValueTask<bool> WaitForNextTickAsync(System.Threading.CancellationToken cancellationToken = default);
}
public interface IPeriodicTimerFactory : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
Testably.Abstractions.TimeSystem.IPeriodicTimer New(System.TimeSpan period);
Testably.Abstractions.TimeSystem.IPeriodicTimer Wrap(System.Threading.PeriodicTimer timer);
}
public interface IStopwatch : Testably.Abstractions.TimeSystem.ITimeSystemEntity
{
System.TimeSpan Elapsed { get; }
Expand Down
35 changes: 22 additions & 13 deletions Tests/Testably.Abstractions.Parity.Tests/ParityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ namespace Testably.Abstractions.Parity.Tests;
public abstract class ParityTests(
TestHelpers.Parity parity)
{
#region Test Setup

public TestHelpers.Parity Parity { get; } = parity;

#endregion

[Test]
public async Task IDirectory_EnsureParityWith_Directory()
{
Expand Down Expand Up @@ -121,23 +117,25 @@ public async Task IPath_EnsureParityWith_Path()
await That(parityErrors).IsEmpty();
}

#if FEATURE_PERIODIC_TIMER
[Test]
public async Task IRandomAndIRandomFactory_EnsureParityWith_Random()
public async Task
IPeriodicTimerAndIPeriodicTimerFactory_EnsureParityWith_PeriodicTimer()
{
List<string> parityErrors = Parity.Random
.GetErrorsToInstanceType<IRandom, IRandomFactory>(
typeof(Random));
List<string> parityErrors = Parity.PeriodicTimer
.GetErrorsToInstanceType<IPeriodicTimer, IPeriodicTimerFactory>(
typeof(PeriodicTimer));

await That(parityErrors).IsEmpty();
}
#endif

[Test]
public async Task
ITimerAndITimerFactory_EnsureParityWith_Timer()
public async Task IRandomAndIRandomFactory_EnsureParityWith_Random()
{
List<string> parityErrors = Parity.Timer
.GetErrorsToInstanceType<ITimer, ITimerFactory>(
typeof(Timer));
List<string> parityErrors = Parity.Random
.GetErrorsToInstanceType<IRandom, IRandomFactory>(
typeof(Random));

await That(parityErrors).IsEmpty();
}
Expand All @@ -156,6 +154,17 @@ public async Task
await That(parityErrors).IsEmpty();
}

[Test]
public async Task
ITimerAndITimerFactory_EnsureParityWith_Timer()
{
List<string> parityErrors = Parity.Timer
.GetErrorsToInstanceType<ITimer, ITimerFactory>(
typeof(Timer));

await That(parityErrors).IsEmpty();
}

[Test]
public async Task IZipArchive_EnsureParityWith_ZipArchive()
{
Expand Down
10 changes: 10 additions & 0 deletions Tests/Testably.Abstractions.Parity.Tests/TestHelpers/Parity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ public class Parity
#pragma warning restore CS0618
});

#if FEATURE_PERIODIC_TIMER
public ParityCheck PeriodicTimer { get; } = new(excludeConstructors:
[
typeof(PeriodicTimer).GetConstructor([
typeof(TimeSpan),
typeof(TimeProvider),
]),
]);
#endif

public ParityCheck Random { get; } = new();

public ParityCheck Stopwatch { get; } = new(excludeMethods:
Expand Down
Loading