Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -33,6 +33,7 @@
<DefineConstants Condition="'$(IS_NET8_OR_HIGHER)' == '1'">$(DefineConstants);FEATURE_GUID_FORMATPROVIDER</DefineConstants>
<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_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;
Comment thread
vbreuss marked this conversation as resolved.

[Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
Expand Down
6 changes: 6 additions & 0 deletions Source/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,10 @@
</PackageReference>
</ItemGroup>

<PropertyGroup>
<!-- The version is only set to support local builds.
In the build pipeline it is overwritten with the actual version in the `nuke Compile` step -->
<Version>255.255.255.255</Version>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
<PackageReference Include="System.IO.FileSystem.AccessControl" />
</ItemGroup>

<ItemGroup>
<ItemGroup Condition=" '$(Configuration)' != 'Debug' ">
<PackageReference Include="Testably.Abstractions.Interface" />
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<ProjectReference Include="..\Testably.Abstractions.Interface\Testably.Abstractions.Interface.csproj" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.CLSCompliant">
<_Parameter1>true</_Parameter1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
Link="Docs\Compression.md" />
</ItemGroup>

<ItemGroup>
<ItemGroup Condition=" '$(Configuration)' != 'Debug' ">
<PackageReference Include="Testably.Abstractions.Interface" />
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<ProjectReference Include="..\Testably.Abstractions.Interface\Testably.Abstractions.Interface.csproj" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Testably.Abstractions.Compression.Tests" PublicKey="$(PublicKey)" />
</ItemGroup>
Expand Down
5 changes: 5 additions & 0 deletions Source/Testably.Abstractions.Interface/ITimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public interface ITimeSystem
/// </summary>
IDateTime DateTime { get; }

/// <summary>
/// Abstractions for <see cref="System.Diagnostics.Stopwatch" />.
/// </summary>
IStopwatchFactory Stopwatch { get; }

/// <summary>
/// Abstractions for <see cref="System.Threading.Tasks.Task" />.
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions Source/Testably.Abstractions.Interface/TimeSystem/IStopwatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Diagnostics;

namespace Testably.Abstractions.TimeSystem;

/// <summary>
/// Abstractions for <see cref="Stopwatch" />.
/// </summary>
public interface IStopwatch : ITimeSystemEntity
{
/// <inheritdoc cref="Stopwatch.Elapsed" />
TimeSpan Elapsed { get; }

/// <inheritdoc cref="Stopwatch.ElapsedMilliseconds" />
long ElapsedMilliseconds { get; }

/// <inheritdoc cref="Stopwatch.ElapsedTicks" />
long ElapsedTicks { get; }

/// <inheritdoc cref="Stopwatch.IsRunning" />
bool IsRunning { get; }

/// <inheritdoc cref="Stopwatch.Reset()" />
void Reset();

/// <inheritdoc cref="Stopwatch.Restart()" />
void Restart();

/// <inheritdoc cref="Stopwatch.Start()" />
void Start();

/// <inheritdoc cref="Stopwatch.Stop()" />
void Stop();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Diagnostics;
Comment thread
vbreuss marked this conversation as resolved.
Outdated

namespace Testably.Abstractions.TimeSystem;

/// <summary>
/// Factory for abstracting creation of <see cref="Stopwatch" />.
/// </summary>
public interface IStopwatchFactory : ITimeSystemEntity
{
/// <inheritdoc cref="Stopwatch.Frequency" />
long Frequency { get; }

/// <inheritdoc cref="Stopwatch.IsHighResolution" />
bool IsHighResolution { get; }

/// <inheritdoc cref="Stopwatch.GetTimestamp()" />
long GetTimestamp();

/// <inheritdoc cref="Stopwatch()" />
IStopwatch New();

/// <inheritdoc cref="Stopwatch.StartNew()" />
IStopwatch StartNew();

/// <summary>
/// Wraps the <paramref name="stopwatch" /> to the testable <see cref="IStopwatch" />.
/// </summary>
IStopwatch Wrap(Stopwatch stopwatch);

#if FEATURE_STOPWATCH_GETELAPSEDTIME
/// <inheritdoc cref="Stopwatch.GetElapsedTime(long)" />
TimeSpan GetElapsedTime(long startingTimestamp);

/// <inheritdoc cref="Stopwatch.GetElapsedTime(long, long)" />
TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp);
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ internal static NotSupportedException NotSupportedSafeFileHandle()
=> new(
"You cannot mock a safe file handle in the mocked file system without registering a strategy explicitly. Use `MockFileSystem.WithSafeFileHandleStrategy`!");

internal static NotSupportedException NotSupportedStopwatchWrapping()
=> new("You cannot wrap an existing Stopwatch in the MockTimeSystem instance!");

internal static NotSupportedException NotSupportedTimerWrapping()
=> new("You cannot wrap an existing Timer in the MockTimeSystem instance!");

Expand Down
16 changes: 11 additions & 5 deletions Source/Testably.Abstractions.Testing/MockTimeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ public INotificationHandler On
/// <summary>
/// The handler for mocked timers.
/// </summary>
public ITimerHandler TimerHandler => _timerMock;
public ITimerHandler TimerHandler => _timerFactoryMock;

private readonly NotificationHandler _callbackHandler;
private readonly DateTimeMock _dateTimeMock;
private readonly StopwatchFactoryMock _stopwatchFactoryMock;
private readonly TaskMock _taskMock;
private readonly ThreadMock _threadMock;
private readonly TimerFactoryMock _timerMock;
private readonly TimerFactoryMock _timerFactoryMock;

/// <summary>
/// Initializes the <see cref="MockTimeSystem" /> with a random time.
Expand All @@ -55,9 +56,10 @@ public MockTimeSystem(ITimeProvider timeProvider)
TimeProvider = timeProvider;
_callbackHandler = new NotificationHandler();
_dateTimeMock = new DateTimeMock(this, _callbackHandler);
_stopwatchFactoryMock = new StopwatchFactoryMock(this);
_threadMock = new ThreadMock(this, _callbackHandler);
_taskMock = new TaskMock(this, _callbackHandler);
_timerMock = new TimerFactoryMock(this);
_timerFactoryMock = new TimerFactoryMock(this);
}

#region ITimeSystem Members
Expand All @@ -66,6 +68,10 @@ public MockTimeSystem(ITimeProvider timeProvider)
public IDateTime DateTime
=> _dateTimeMock;

/// <inheritdoc cref="ITimeSystem.Stopwatch" />
public IStopwatchFactory Stopwatch
=> _stopwatchFactoryMock;

/// <inheritdoc cref="ITimeSystem.Task" />
public ITask Task
=> _taskMock;
Expand All @@ -76,7 +82,7 @@ public IThread Thread

/// <inheritdoc cref="ITimeSystem.Timer" />
public ITimerFactory Timer
=> _timerMock;
=> _timerFactoryMock;

#endregion

Expand All @@ -90,7 +96,7 @@ public override string ToString()
/// <param name="timerStrategy">The timer strategy. </param>
public MockTimeSystem WithTimerStrategy(ITimerStrategy timerStrategy)
{
_timerMock.SetTimerStrategy(timerStrategy);
_timerFactoryMock.SetTimerStrategy(timerStrategy);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
<None Include="$(SolutionDir)Docs/Nuget/Testing.md" Pack="true" PackagePath="/Docs/" Link="Docs\Testing.md" />
</ItemGroup>

<ItemGroup>
<ItemGroup Condition=" '$(Configuration)' != 'Debug' ">
<PackageReference Include="Testably.Abstractions.Interface" />
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<ProjectReference Include="..\Testably.Abstractions.Interface\Testably.Abstractions.Interface.csproj" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.CLSCompliant">
<_Parameter1>true</_Parameter1>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Diagnostics;
using Testably.Abstractions.Testing.Helpers;
using Testably.Abstractions.TimeSystem;
using IStopwatch = Testably.Abstractions.TimeSystem.IStopwatch;

namespace Testably.Abstractions.Testing.TimeSystem;

internal sealed class StopwatchFactoryMock : IStopwatchFactory
{
private readonly MockTimeSystem _mockTimeSystem;

internal StopwatchFactoryMock(MockTimeSystem timeSystem)
{
_mockTimeSystem = timeSystem;
}

#region IStopwatchFactory Members

/// <inheritdoc cref="IStopwatchFactory.Frequency" />
public long Frequency => TimeSpan.TicksPerSecond;

/// <inheritdoc cref="IStopwatchFactory.IsHighResolution" />
public bool IsHighResolution => true;

/// <inheritdoc cref="ITimeSystemEntity.TimeSystem" />
public ITimeSystem TimeSystem
=> _mockTimeSystem;

#if FEATURE_STOPWATCH_GETELAPSEDTIME
/// <inheritdoc cref="IStopwatchFactory.GetElapsedTime(long)" />
public TimeSpan GetElapsedTime(long startingTimestamp)
=> GetElapsedTime(startingTimestamp, GetTimestamp());
#endif

#if FEATURE_STOPWATCH_GETELAPSEDTIME
/// <inheritdoc cref="IStopwatchFactory.GetElapsedTime(long, long)" />
public TimeSpan GetElapsedTime(long startingTimestamp, long endingTimestamp)
=> TimeSpan.FromTicks(endingTimestamp - startingTimestamp);
#endif

/// <inheritdoc cref="IStopwatchFactory.GetTimestamp()" />
public long GetTimestamp()
=> _mockTimeSystem.TimeProvider.Read().Ticks;

/// <inheritdoc cref="IStopwatchFactory.New()" />
public IStopwatch New()
{
StopwatchMock stopwatchMock = new(_mockTimeSystem);
return stopwatchMock;
}

/// <inheritdoc cref="IStopwatchFactory.StartNew()" />
public IStopwatch StartNew()
{
IStopwatch stopwatch = New();
stopwatch.Start();
return stopwatch;
}

/// <inheritdoc cref="IStopwatchFactory.Wrap(Stopwatch)" />
public IStopwatch Wrap(Stopwatch stopwatch)
=> throw ExceptionFactory.NotSupportedStopwatchWrapping();

#endregion
}
82 changes: 82 additions & 0 deletions Source/Testably.Abstractions.Testing/TimeSystem/StopwatchMock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using Testably.Abstractions.TimeSystem;

namespace Testably.Abstractions.Testing.TimeSystem;

internal sealed class StopwatchMock : IStopwatch
{
private long _elapsedTicks;
private readonly MockTimeSystem _mockTimeSystem;
private DateTime? _start;

internal StopwatchMock(MockTimeSystem timeSystem)
{
_mockTimeSystem = timeSystem;
}

#region IStopwatch Members

/// <inheritdoc cref="IStopwatch.Elapsed" />
public TimeSpan Elapsed
=> new(ElapsedTicks);

/// <inheritdoc cref="IStopwatch.ElapsedMilliseconds" />
public long ElapsedMilliseconds
=> ElapsedTicks / TimeSpan.TicksPerMillisecond;

/// <inheritdoc cref="IStopwatch.ElapsedTicks" />
public long ElapsedTicks
{
get
{
long timeElapsed = _elapsedTicks;

// If the Stopwatch is running, add elapsed time since the Stopwatch is started last time.
if (_start is not null)
{
timeElapsed += (_mockTimeSystem.TimeProvider.Read() - _start.Value).Ticks;
}

return timeElapsed;
}
}

/// <inheritdoc cref="IStopwatch.IsRunning" />
public bool IsRunning => _start is not null;

/// <inheritdoc cref="ITimeSystemEntity.TimeSystem" />
public ITimeSystem TimeSystem
=> _mockTimeSystem;

/// <inheritdoc cref="IStopwatch.Reset()" />
public void Reset()
{
Stop();
_elapsedTicks = 0;
}

/// <inheritdoc cref="IStopwatch.Restart()" />
public void Restart()
{
Reset();
Start();
}

/// <inheritdoc cref="IStopwatch.Start()" />
public void Start()
{
_start = _mockTimeSystem.TimeProvider.Read();
Comment thread
vbreuss marked this conversation as resolved.
Outdated
}

/// <inheritdoc cref="IStopwatch.Stop()" />
public void Stop()
{
if (_start.HasValue)
{
_elapsedTicks += (_mockTimeSystem.TimeProvider.Read() - _start.Value).Ticks;
_start = null;
}
}

#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public ITimer New(TimerCallback callback, object? state, TimeSpan dueTime, TimeS
return RegisterTimerMock(timerMock);
}

/// <inheritdoc cref="IFileStreamFactory.Wrap(FileStream)" />
/// <inheritdoc cref="ITimerFactory.Wrap(Timer)" />
public ITimer Wrap(Timer timer)
=> throw ExceptionFactory.NotSupportedTimerWrapping();

Expand Down
Loading
Loading